home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 September / CHIP_CD_2004-09.iso / software / httrack / httrack-3.32-2.exe / {app} / src / htscore.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-08  |  111.7 KB  |  3,602 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Main source                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. #include <fcntl.h>
  41. #include <ctype.h>
  42.  
  43. /* File defs */
  44. #include "htscore.h"
  45.  
  46. /* specific definitions */
  47. #include "htsbase.h"
  48. #include "htsnet.h"
  49. #include "htsbauth.h"
  50. #include "htsmd5.h"
  51. #include "htsindex.h"
  52.  
  53. /* external modules */
  54. #include "htsmodules.h"
  55.  
  56. // htswrap_add
  57. #include "htswrap.h"
  58.  
  59. // parser
  60. #include "htsparse.h"
  61.  
  62. /* Cache */
  63. #include "htszlib.h"
  64.  
  65.  
  66. /* END specific definitions */
  67.  
  68.  
  69. /* HTML parsing */
  70. #if HTS_ANALYSTE
  71.  
  72. t_hts_htmlcheck_init    hts_htmlcheck_init = NULL;
  73. t_hts_htmlcheck_uninit  hts_htmlcheck_uninit = NULL;
  74. t_hts_htmlcheck_start   hts_htmlcheck_start = NULL;
  75. t_hts_htmlcheck_end     hts_htmlcheck_end = NULL;
  76. t_hts_htmlcheck_chopt   hts_htmlcheck_chopt = NULL;
  77. t_hts_htmlcheck         hts_htmlcheck = NULL;
  78. t_hts_htmlcheck_query   hts_htmlcheck_query = NULL;
  79. t_hts_htmlcheck_query2  hts_htmlcheck_query2 = NULL;
  80. t_hts_htmlcheck_query3  hts_htmlcheck_query3 = NULL;
  81. t_hts_htmlcheck_loop    hts_htmlcheck_loop = NULL;
  82. t_hts_htmlcheck_check   hts_htmlcheck_check = NULL;
  83. t_hts_htmlcheck_pause   hts_htmlcheck_pause = NULL;
  84. t_hts_htmlcheck_filesave       hts_htmlcheck_filesave = NULL;
  85. t_hts_htmlcheck_linkdetected   hts_htmlcheck_linkdetected = NULL;
  86. t_hts_htmlcheck_xfrstatus hts_htmlcheck_xfrstatus = NULL;
  87. t_hts_htmlcheck_savename  hts_htmlcheck_savename = NULL;
  88. t_hts_htmlcheck_sendhead  hts_htmlcheck_sendhead = NULL;
  89. t_hts_htmlcheck_receivehead  hts_htmlcheck_receivehead = NULL;
  90.  
  91.  
  92. char _hts_errmsg[1100]="";
  93. int _hts_in_html_parsing=0;
  94. int _hts_in_html_done=0;  // % done
  95. int _hts_in_html_poll=0;  // parsing
  96. int _hts_setpause=0;
  97. //httrackp* _hts_setopt=NULL;
  98. char** _hts_addurl=NULL;
  99.  
  100. /* external modules */
  101. extern int hts_parse_externals(htsmoduleStruct* str);
  102. extern void htspe_init(void);
  103.  
  104. //
  105. int _hts_cancel=0;
  106. #endif
  107.  
  108.  
  109.  
  110. int exit_xh;          /* quick exit (fatal error or interrupt) */
  111.  
  112. /* debug */
  113. #if DEBUG_SHOWTYPES
  114. char REG[32768]="\n";
  115. #endif
  116. #if NSDEBUG
  117. int nsocDEBUG=0;
  118. #endif
  119.  
  120. //
  121. #define _CLRSCR printf("\33[m\33[2J");
  122. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  123.  
  124. #if DEBUG_CHECKINT
  125.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  126.  #define _CHECKINT(obj_ptr,message) \
  127.    if (obj_ptr) {\
  128.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  129.        char msg[1100];\
  130.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  131.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  132.        else if ( * ((char*) (obj_ptr)) != 0)\
  133.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  134.        else\
  135.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  136.        _CHECKINT_FAIL(msg);\
  137.      }\
  138.    } else {\
  139.      char msg[1100];\
  140.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  141.      _CHECKINT_FAIL(msg);\
  142.    }
  143. #endif
  144.  
  145. #if DEBUG_HASH
  146.   // longest hash chain?
  147.   int longest_hash[3]={0,0,0},hashnumber=0;
  148. #endif
  149.  
  150. // demande d'interaction avec le shell
  151. #if HTS_ANALYSTE
  152. char HTbuff[2048];
  153. #endif
  154.  
  155.  
  156.  
  157. // DΘbut de httpmirror, routines annexes
  158.  
  159. // version 1 pour httpmirror
  160. // flusher si on doit lire peu α peu le fichier
  161. #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
  162.  
  163. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  164. #define urladr   (liens[ptr]->adr)
  165. #define urlfil   (liens[ptr]->fil)
  166. #define savename (liens[ptr]->sav)
  167. //#define level    (liens[ptr]->depth)
  168.  
  169. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  170. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  171. // ne sont plus α nous.. agh! [dur celui-lα]
  172. #if HTS_ANALYSTE
  173. #define HTMLCHECK_UNINIT { \
  174. if ( (opt.debug>0) && (opt.log!=NULL) ) { \
  175. fspc(opt.log,"info"); fprintf(opt.log,"engine: end"LF); \
  176. } \
  177. hts_htmlcheck_end(); \
  178. }
  179. #else
  180.  #define HTMLCHECK_UNINIT 
  181. #endif
  182.  
  183. #define XH_extuninit do { \
  184.   int i; \
  185.   HTMLCHECK_UNINIT \
  186.   if (liens!=NULL) { \
  187.   for(i=lien_max-1;i>=0;i--) { \
  188.   if (liens[i]) { \
  189.   if (liens[i]->firstblock==1) { \
  190.   freet(liens[i]); \
  191.   liens[i]=NULL; \
  192.   } \
  193.   } \
  194.   } \
  195.   freet(liens); \
  196.   liens=NULL; \
  197.   } \
  198.   if (filters && filters[0]) { \
  199.   freet(filters[0]); filters[0]=NULL; \
  200.   } \
  201.   if (filters) { \
  202.   freet(filters); filters=NULL; \
  203.   } \
  204.   if (back) { \
  205.   int i; \
  206.   for(i=0;i<back_max;i++) { \
  207.   back_delete(&opt,&cache,back,i); \
  208.   } \
  209.   freet(back); back=NULL;  \
  210.   } \
  211.   checkrobots_free(&robots);\
  212.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  213.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  214.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  215.   if (cache.zipOutput) { \
  216.     zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
  217.     cache.zipOutput = NULL; \
  218.   } \
  219.   if (cache.zipInput) { \
  220.     unzClose(cache.zipInput); \
  221.     cache.zipInput = NULL; \
  222.   } \
  223.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  224.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  225.   if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
  226.   if (opt.log) fflush(opt.log); \
  227.   if (opt.errlog) fflush(opt.errlog);\
  228.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  229.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  230.   if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
  231.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  232.   if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
  233.   if (cache_tests)     { inthash_delete(&cache_tests); } \
  234.   if (template_header) { freet(template_header); template_header=NULL; } \
  235.   if (template_body)   { freet(template_body); template_body=NULL; } \
  236.   if (template_footer) { freet(template_footer); template_footer=NULL; } \
  237.   clearCallbacks(&opt.state.callbacks); \
  238.   /*structcheck_init(-1);*/ \
  239. } while(0)
  240. #define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
  241.  
  242. // Enregistrement d'un lien:
  243. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  244. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  245. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  246. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  247. // FA,FS: former_adr et former_fil, lien original
  248. #if HTS_HASH
  249. #define liens_record_sav_len(A) 
  250. #else
  251. #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
  252. #endif
  253.  
  254. #define liens_record(A,F,S,FA,FF,NORM) { \
  255. int notecode=0; \
  256. int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  257.   adr_len=strlen(A),\
  258.   fil_len=strlen(F),\
  259.   sav_len=strlen(S),\
  260.   cod_len=0,\
  261.   former_adr_len=strlen(FA),\
  262.   former_fil_len=strlen(FF); \
  263. if (former_adr_len>0) {\
  264.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  265.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  266. } else former_adr_len=former_fil_len=0;\
  267. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  268. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  269. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  270. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  271. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  272. lien_size=add_tab_alloc; \
  273. if (lien_buffer!=NULL) { \
  274. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  275. liens[lien_tot]->firstblock=1; \
  276. } \
  277. } else { \
  278. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  279. liens[lien_tot]->firstblock=0; \
  280. } \
  281. if (liens[lien_tot]!=NULL) { \
  282. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  283. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  284. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  285. liens[lien_tot]->cod=NULL; \
  286. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  287. if (former_adr_len>0) {\
  288. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  289. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  290. strcpybuff(liens[lien_tot]->former_adr,FA); \
  291. strcpybuff(liens[lien_tot]->former_fil,FF); \
  292. }\
  293. strcpybuff(liens[lien_tot]->adr,A); \
  294. strcpybuff(liens[lien_tot]->fil,F); \
  295. strcpybuff(liens[lien_tot]->sav,S); \
  296. liens_record_sav_len(liens[lien_tot]); \
  297. hash_write(hashptr,lien_tot,NORM);  \
  298. } \
  299. }
  300.  
  301.  
  302. #define HT_INDEX_END do { \
  303. if (!makeindex_done) { \
  304. if (makeindex_fp) { \
  305.   char tempo[1024]; \
  306.   if (makeindex_links == 1) { \
  307.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  308.   } else \
  309.     tempo[0]='\0'; \
  310.   fprintf(makeindex_fp,template_footer, \
  311.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  312.     tempo \
  313.     ); \
  314.   fflush(makeindex_fp); \
  315.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  316.   makeindex_fp=NULL; \
  317.   usercommand(&opt,0,NULL,fconcat(opt.path_html,"index.html"),"","");  \
  318. } \
  319. } \
  320. makeindex_done=1;    /* ok c'est fait */  \
  321. } while(0)
  322.  
  323.  
  324.  
  325.  
  326. // DΘbut de httpmirror, robot
  327. // url1 peut Ωtre multiple
  328. int httpmirror(char* url1,httrackp* ptropt) {
  329.   httrackp opt = *ptropt;      // structure d'options
  330.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  331.   int lien_tot=0;              // nombre de liens pour le moment
  332.   lien_url** liens=NULL;       // les pointeurs sur les liens
  333.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  334.   hash_struct* hashptr = &hash;
  335.   t_cookie cookie;             // gestion des cookies
  336.   int lien_max=0;
  337.   int lien_size=0;        // octets restants dans buffer liens dispo
  338.   char* lien_buffer=NULL; // buffer liens actuel
  339.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  340.   //char* tab_alloc=NULL;
  341.   int ptr;             // pointeur actuel sur les liens
  342.   //
  343.   int numero_passe=0;  // deux passes pour html puis images
  344.   int back_max=0;      // fichiers qui peuvent Ωtre en local
  345.   lien_back* back=NULL; // backing en local
  346.   htsblk r;            // retour de certaines fonctions
  347.   TStamp lastime=0;    // pour affichage infos de tmp en tmp
  348.   // pour les stats, nombre de fichiers & octets Θcrits
  349.   LLint stat_fragment=0;  // pour la fragmentation
  350.   //TStamp istat_timestart;   // dΘpart pour calcul instantannΘ
  351.   //
  352.   TStamp last_info_shell=0;
  353.   int info_shell=0;
  354.   // filtres
  355.   char** filters = NULL;
  356.   //int filter_max=0;
  357.   int filptr=0;
  358.   //
  359.   int makeindex_done=0;  // lorsque l'index sera fait
  360.   FILE* makeindex_fp=NULL;
  361.   int makeindex_links=0;
  362.   char makeindex_firstlink[HTS_URLMAXSIZE*2];
  363.   // statistiques (mode #Z)
  364.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  365.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  366.   TStamp makestat_time=0;    // attente (secondes)
  367.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  368.   int makestat_lnk=0;        // idem, pour le nombre de liens
  369.   //
  370.   char codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  371.   char base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  372.   //
  373.   cache_back cache;
  374.   robots_wizard robots;    // gestion robots.txt
  375.   inthash cache_hashtable=NULL;
  376.   inthash cache_tests=NULL;
  377.   int cache_hash_size=0;
  378.   //
  379.   char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
  380.   //
  381.   codebase[0]='\0'; base[0]='\0';
  382.   //
  383.   cookie.auth.next=NULL;
  384.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  385.   //
  386.  
  387.   // noter heure actuelle de dΘpart en secondes
  388.   memset(&HTS_STAT, 0, sizeof(HTS_STAT));
  389.   HTS_STAT.stat_timestart=time_local();
  390.   //istat_timestart=stat_timestart;
  391.   HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
  392.   /* reset stats */
  393.   HTS_STAT.HTS_TOTAL_RECV=0;
  394.   HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
  395.   /*
  396.   if (opt.aff_progress)
  397.     lastime=HTS_STAT.stat_timestart;
  398.     */
  399.   if (opt.shell) {
  400.     last_info_shell=HTS_STAT.stat_timestart;
  401.   }
  402.   if ((opt.makestat) || (opt.maketrack)){
  403.     makestat_time=HTS_STAT.stat_timestart;
  404.   }
  405.   // initialiser compteur erreurs
  406.   fspc(NULL,NULL);
  407.  
  408.   // init external modules
  409.   htspe_init();
  410.  
  411.   // initialiser cookie
  412.   if (opt.accept_cookie) {
  413.     opt.cookie=&cookie;
  414.     cookie.max_len=30000;       // max len
  415.     strcpybuff(cookie.data,"");
  416.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  417.     cookie_load(opt.cookie,opt.path_log,"cookies.txt");
  418.     cookie_load(opt.cookie,"","cookies.txt");
  419.   } else
  420.     opt.cookie=NULL;
  421.  
  422.   // initialiser exit_xh
  423.   exit_xh=0;          // sortir prΘmaturΘment (var globale)
  424.  
  425.   // initialiser usercommand
  426.   usercommand(&opt,opt.sys_com_exec,opt.sys_com,"","","");
  427.  
  428.   // initialiser structcheck
  429.   // structcheck_init(1);
  430.  
  431.   // initialiser tableau options accessible par d'autres fonctions (signal)
  432.   hts_declareoptbuffer(&opt);
  433.  
  434.   // initialiser verif_backblue
  435.   verif_backblue(&opt,NULL);
  436.   verif_external(0,0);
  437.   verif_external(1,0);
  438.  
  439.   // et templates html
  440.   template_header=readfile_or(fconcat(opt.path_bin,"templates/index-header.html"),HTS_INDEX_HEADER);
  441.   template_body=readfile_or(fconcat(opt.path_bin,"templates/index-body.html"),HTS_INDEX_BODY);
  442.   template_footer=readfile_or(fconcat(opt.path_bin,"templates/index-footer.html"),HTS_INDEX_FOOTER);
  443.  
  444.   // initialiser mimedefs
  445.   get_userhttptype(1,opt.mimedefs,NULL);
  446.  
  447.   // Initialiser indexation
  448.   if (opt.kindex)
  449.     index_init(opt.path_html);
  450.  
  451.   // effacer bloc cache
  452.   memset(&cache, 0, sizeof(cache_back));
  453.   cache.type=opt.cache;  // cache?
  454.   cache.errlog=opt.errlog;  // err log?
  455.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  456.  
  457.   // initialiser hash cache
  458.   if (!cache_hash_size) 
  459.     cache_hash_size=HTS_HASH_SIZE;
  460.   cache_hashtable=inthash_new(cache_hash_size);
  461.   cache_tests=inthash_new(cache_hash_size);
  462.   if (cache_hashtable==NULL || cache_tests==NULL) {
  463.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  464.     filters[0]=NULL; back_max=0;    // uniquement a cause du warning de XH_extuninit
  465.     XH_extuninit;
  466.     return 0;
  467.   }
  468.   inthash_value_is_malloc(cache_tests, 1);     /* malloc */
  469.   cache.hashtable=(void*)cache_hashtable;      /* copy backcache hash */
  470.   cache.cached_tests=(void*)cache_tests;      /* copy of cache_tests */
  471.  
  472.   // initialiser cache DNS
  473.   _hts_lockdns(-999);
  474.   
  475.   // robots.txt
  476.   strcpybuff(robots.adr,"!");    // dummy
  477.   robots.token[0]='\0';
  478.   robots.next=NULL;          // suivant
  479.   opt.robotsptr = &robots;
  480.   
  481.   // effacer filters
  482.   opt.maxfilter = maximum(opt.maxfilter, 128);
  483.   if (filters_init(&filters, opt.maxfilter, 0) == 0) {
  484.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  485.     back_max=0;    // uniquement a cause du warning de XH_extuninit
  486.     XH_extuninit;
  487.     return 0;
  488.   }
  489.   opt.filters.filters=&filters;
  490.   //
  491.   opt.filters.filptr=&filptr;
  492.   //opt.filters.filter_max=&filter_max;
  493.   
  494.   // hash table
  495.   opt.hash = &hash;
  496.  
  497.   // tableau de pointeurs sur les liens
  498.   lien_max=maximum(opt.maxlink,32);
  499.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  500.   if (liens==NULL) {
  501.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  502.     //XH_uninit;
  503.     return 0;
  504.   } else {
  505.     int i;
  506.     for(i=0;i<lien_max;i++) {
  507.       liens[i]=NULL;     
  508.     }
  509.   }
  510.   // initialiser ptr et lien_tot
  511.   ptr=0;
  512.   lien_tot=0;
  513. #if HTS_HASH
  514.   // initialiser hachage
  515.   {
  516.     int i;
  517.     for(i=0;i<HTS_HASH_SIZE;i++)
  518.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  519.     hash.liens = liens;
  520.     hash.max_lien=0;
  521.   }
  522. #endif
  523.  
  524.   
  525.   // copier adresse(s) dans liste des adresses
  526.   {
  527.     char *a=url1;
  528.     int primary_len=8192;
  529.     if (strnotempty(opt.filelist)) {
  530.       primary_len+=max(0,fsize(opt.filelist)*2);
  531.     }
  532.     primary_len+=strlen(url1)*2;
  533.  
  534.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  535.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  536.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  537.     primary=(char*) malloct(primary_len); 
  538.     if (primary) {
  539.       primary[0]='\0';
  540.     } else {
  541.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  542.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  543.       XH_extuninit;
  544.       return 0;
  545.     }
  546.     
  547.     while(*a) {
  548.       int i;
  549.       int joker=0;
  550.  
  551.       // vΘrifier qu'il n'y a pas de * dans l'url
  552.       if (*a=='+')
  553.         joker=1;
  554.       else if (*a=='-')
  555.         joker=1;
  556.       
  557.       if (joker) {    // joker ou filters
  558.         //char* p;
  559.         char tempo[HTS_URLMAXSIZE*2];
  560.         int type; int plus=0;
  561.  
  562.         // noter joker (dans b)
  563.         if (*a=='+') {  // champ +
  564.           type=1; plus=1; a++;
  565.         } else if (*a=='-') {  // champ forbidden[]
  566.           type=0; a++;
  567.         } else {  // champ + avec joker sans doute
  568.           type=1;
  569.         }
  570.  
  571.         // recopier prochaine chaine (+ ou -)
  572.         i=0;
  573.         while((*a!=0) && (!isspace((unsigned char)*a))) { tempo[i++]=*a; a++; }  
  574.         tempo[i++]='\0';
  575.         while(isspace((unsigned char)*a)) { a++; }
  576.  
  577.         // sauter les + sans rien aprΦs..
  578.         if (strnotempty(tempo)) {
  579.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  580.             if (tempo[strlen(tempo)-1]!='*') {
  581.               strcatbuff(tempo,"*");  // ajouter un *
  582.             }
  583.           }
  584.           if (type)
  585.             strcpybuff(filters[filptr],"+");
  586.           else
  587.             strcpybuff(filters[filptr],"-");
  588.           /*
  589.           if (strfield(tempo,"http://"))
  590.             strcatbuff(filters[filptr],tempo+7);        // ignorer http://
  591.           else if (strfield(tempo,"ftp://"))
  592.             strcatbuff(filters[filptr],tempo+6);        // ignorer ftp://
  593.           else
  594.           */
  595.           strcatbuff(filters[filptr],tempo);
  596.           filptr++;
  597.           
  598.           /* sanity check */
  599.           if (filptr + 1 >= opt.maxfilter) {
  600.             opt.maxfilter += HTS_FILTERSINC;
  601.             if (filters_init(&filters, opt.maxfilter, HTS_FILTERSINC) == 0) {
  602.               printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
  603.               if (opt.errlog) {
  604.                 fprintf(opt.errlog,LF"Too many filters, giving up..(>%d)"LF,filptr);
  605.                 fprintf(opt.errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  606.                 test_flush;
  607.               }
  608.               back_max=0;    // uniquement a cause du warning de XH_extuninit
  609.               XH_extuninit;
  610.               return 0;
  611.             }
  612.             //opt.filters.filters=filters;
  613.           }
  614.  
  615.         }
  616.         
  617.       } else {    // adresse normale
  618.         char url[HTS_URLMAXSIZE*2];
  619.         // prochaine adresse
  620.         i=0;
  621.         while((*a!=0) && (!isspace((unsigned char)*a))) { url[i++]=*a; a++; }  
  622.         while(isspace((unsigned char)*a)) { a++; }
  623.         url[i++]='\0';
  624.  
  625.         //strcatbuff(primary,"<PRIMARY=\"");
  626.         if (strstr(url,":/")==NULL)
  627.           strcatbuff(primary,"http://");
  628.         strcatbuff(primary,url);
  629.         //strcatbuff(primary,"\">");
  630.         strcatbuff(primary,"\n");
  631.       }
  632.     }  // while
  633.  
  634.     /* load URL file list */
  635.     /* OPTIMIZED for fast load */
  636.     if (strnotempty(opt.filelist)) {
  637.       char* filelist_buff=NULL;
  638.       INTsys filelist_sz=fsize(opt.filelist);
  639.       if (filelist_sz>0) {
  640.         FILE* fp=fopen(opt.filelist,"rb");
  641.         if (fp) {
  642.           filelist_buff=malloct(filelist_sz + 2);
  643.           if (filelist_buff) {
  644.             if ((INTsys)fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
  645.               freet(filelist_buff);
  646.               filelist_buff=NULL;
  647.             } else {
  648.               *(filelist_buff + filelist_sz) = '\0';
  649.             }
  650.           }
  651.           fclose(fp);
  652.         }
  653.       }
  654.       
  655.       if (filelist_buff) {
  656.         int filelist_ptr=0;
  657.         int n=0;
  658.         char line[HTS_URLMAXSIZE*2];
  659.         char* primary_ptr = primary + strlen(primary);
  660.         while( filelist_ptr < filelist_sz ) {
  661.           int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
  662.           filelist_ptr+=count;
  663.           if (count && line[0]) {
  664.             n++;
  665.             if (strstr(line,":/")==NULL) {
  666.               strcpybuff(primary_ptr, "http://");
  667.               primary_ptr += strlen(primary_ptr);
  668.             }
  669.             strcpybuff(primary_ptr, line);
  670.             primary_ptr += strlen(primary_ptr);
  671.             strcpybuff(primary_ptr, "\n");
  672.             primary_ptr += 1;
  673.           }
  674.         }
  675.         // fclose(fp);
  676.         if (opt.log!=NULL) {
  677.           fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
  678.         }
  679.  
  680.         // Free buffer
  681.         freet(filelist_buff);
  682.       } else {
  683.         if (opt.errlog!=NULL) {
  684.           fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
  685.         }
  686.       }
  687.     }
  688.  
  689.  
  690.     // lien primaire
  691.     liens_record("primary","/primary",fslash(fconcat(opt.path_html,"index.html")),"","",opt.urlhack);
  692.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  693.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  694.       if (opt.errlog) {
  695.         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  696.         test_flush;
  697.       }
  698.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  699.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  700.       return 0;
  701.     }    
  702.     liens[lien_tot]->testmode=0;          // pas mode test
  703.     liens[lien_tot]->link_import=0;       // pas mode import
  704.     liens[lien_tot]->depth=opt.depth+1;   // lien de prioritΘ maximale
  705.     liens[lien_tot]->pass2=0;             // 1Φre passe
  706.     liens[lien_tot]->retry=opt.retry;     // lien de prioritΘ maximale
  707.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  708.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  709.     lien_tot++;  
  710.  
  711.     // Initialiser cache
  712.     {
  713.       int backupXFR = htsMemoryFastXfr;
  714. #if HTS_ANALYSTE
  715.       _hts_in_html_parsing=4;
  716. #endif
  717.       if (!hts_htmlcheck_loop(NULL,0,0,0,lien_tot,0,NULL)) {
  718.         exit_xh=1;  // exit requested
  719.       }
  720.       htsMemoryFastXfr = 1;               /* fast load */
  721.       cache_init(&cache,&opt);
  722.       htsMemoryFastXfr = backupXFR;
  723. #if HTS_ANALYSTE
  724.       _hts_in_html_parsing=0;
  725. #endif
  726.     }
  727.  
  728.   }
  729.   
  730. #if BDEBUG==3
  731.   {
  732.     int i;
  733.     for(i=0;i<lien_tot;i++) {
  734.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  735.     }
  736.     for(i=0;i<filptr;i++) {
  737.       printf("%d>filters=%s\n",i,filters[i]);
  738.     }
  739.   }
  740. #endif
  741.    
  742.   // backing
  743.   //soc_max=opt.maxsoc;
  744.   if (opt.maxsoc>0) {
  745. #if BDEBUG==2
  746.     _CLRSCR;
  747. #endif
  748.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  749.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  750.     // fichiers non html sont sauvΘs en direct sur disque.
  751.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  752.     back_max=opt.maxsoc*32+1024;
  753.     //back_max=opt.maxsoc*8+32;
  754.     back=(lien_back*) calloct((back_max+1),sizeof(lien_back));
  755.     if (back==NULL) {
  756.       if (opt.errlog)
  757.         fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(int)((opt.maxsoc+1)*sizeof(lien_back)));
  758.       return 0;
  759.     } else {    // copier buffer-location & effacer
  760.       int i;
  761.       for(i=0;i<back_max;i++){
  762.         back[i].r.location=back[i].location_buffer;
  763.         back[i].status=-1;
  764.         back[i].r.soc=INVALID_SOCKET;
  765.       }
  766.     }
  767.   }
  768.  
  769.  
  770.   // flush
  771.   test_flush;
  772.  
  773.   // statistiques
  774.   if (opt.makestat) {
  775.     makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
  776.     if (makestat_fp != NULL) {
  777.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  778.       fflush(makestat_fp);
  779.     }
  780.   }
  781.  
  782.   // tracking -- dΘbuggage
  783.   if (opt.maketrack) {
  784.     maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
  785.     if (maketrack_fp != NULL) {
  786.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  787.       fflush(maketrack_fp);
  788.     }
  789.   }
  790.  
  791.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  792.   if (lien_tot<=0) {
  793.     if (opt.errlog) {
  794.       fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  795.     }
  796.   }
  797.  
  798.   /* Send options to callback functions */
  799. #if HTS_ANALYSTE
  800.   hts_htmlcheck_chopt(&opt);
  801. #endif
  802.  
  803.   // attendre une certaine heure..
  804.   if (opt.waittime>0) {
  805.     int rollover=0;
  806.     int ok=0;
  807.     {
  808.       TStamp tl=0;
  809.       time_t tt;
  810.       struct tm* A;
  811.       tt=time(NULL);
  812.       A=localtime(&tt);
  813.       tl+=A->tm_sec;
  814.       tl+=A->tm_min*60;
  815.       tl+=A->tm_hour*60*60;
  816.       if (tl>opt.waittime)  // attendre minuit
  817.         rollover=1;
  818.     }
  819.  
  820.     // attendre..
  821.     do {
  822.       TStamp tl=0;
  823.       time_t tt;
  824.       struct tm* A;
  825.       tt=time(NULL);
  826.       A=localtime(&tt);
  827.       tl+=A->tm_sec;
  828.       tl+=A->tm_min*60;
  829.       tl+=A->tm_hour*60*60;
  830.  
  831.       if (rollover) {
  832.         if (tl<=opt.waittime)
  833.           rollover=0;  // attendre heure
  834.       } else {
  835.         if (tl>opt.waittime)
  836.           ok=1;  // ok!
  837.       }
  838.       
  839. #if HTS_ANALYSTE
  840.       {  
  841.         int r;
  842.         if (rollover)
  843.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl+24*3600),NULL);
  844.         else
  845.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl),NULL);
  846.         if (!r) {
  847.           exit_xh=1;  // exit requested
  848.           ok=1;          
  849.         } else
  850.           Sleep(100);
  851.       }
  852. #endif
  853.     } while(!ok);    
  854.     
  855.     // note: recopie de plus haut
  856.     // noter heure actuelle de dΘpart en secondes
  857.     HTS_STAT.stat_timestart=time_local();
  858.     /*
  859.     if (opt.aff_progress)
  860.       lastime=HTS_STAT.stat_timestart;
  861.       */
  862.     if (opt.shell) {
  863.       last_info_shell=HTS_STAT.stat_timestart;
  864.     }
  865.     if ((opt.makestat) || (opt.maketrack)){
  866.       makestat_time=HTS_STAT.stat_timestart;
  867.     }
  868.  
  869.  
  870.   }  
  871.   /* Info for wrappers */
  872.   if ( (opt.debug>0) && (opt.log!=NULL) ) {
  873.     fspc(opt.log,"info"); fprintf(opt.log,"engine: start"LF);
  874.   }
  875. #if HTS_ANALYSTE
  876.   if (!hts_htmlcheck_start(&opt)) {
  877.     XH_extuninit;
  878.     return 1;
  879.   }
  880. #endif
  881.   
  882.  
  883.   // ------------------------------------------------------------
  884.  
  885.   // ------------------------------------------------------------
  886.   // Boucle gΘnΘrale de parcours des liens
  887.   // ------------------------------------------------------------
  888.   do {
  889.     int error=0;          // si error alors sauter
  890.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  891.     char loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  892.  
  893.     // Ici on charge le fichier (html, gif..) en mΘmoire
  894.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  895.  
  896.     // effacer r
  897.     memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  898.     r.location=loc;    // en cas d'erreur 3xx (moved)
  899.     // recopier proxy
  900.     memcpy(&(r.req.proxy), &opt.proxy, sizeof(opt.proxy));
  901.     // et user-agent
  902.     strcpybuff(r.req.user_agent,opt.user_agent);
  903.     strcpybuff(r.req.referer,opt.referer);
  904.     strcpybuff(r.req.from,opt.from);
  905.     strcpybuff(r.req.lang_iso,opt.lang_iso);
  906.     r.req.user_agent_send=opt.user_agent_send;
  907.  
  908.     if (!error) {
  909.       
  910.       // Skip empty/invalid/done in background
  911.       if (liens[ptr]) {
  912.         while (  (liens[ptr]) && (
  913.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  914.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  915.                     ( (liens[ptr]->pass2 == -1) )
  916.                  )
  917.                ) {  // sauter si lien annulΘ (ou fil vide)
  918.           if ((opt.debug>1) && (opt.log!=NULL)) {
  919.             fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  920.             test_flush;
  921.           }
  922.           ptr++;
  923.         }
  924.       }
  925.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  926.  
  927.         if ( (opt.debug>1) && (opt.log!=NULL) ) {
  928.           fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
  929.           test_flush;
  930. #if DEBUG_ROBOTS
  931.           if (strcmp(urlfil,"/robots.txt") == 0) {
  932.             printf("robots.txt detected\n");
  933.           }
  934. #endif
  935.         }    
  936.         // ------------------------------------------------------------
  937.         // DEBUT --RECUPERATION LIEN---
  938.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  939.           r.adr=primary; primary=NULL;
  940.           r.statuscode=200;
  941.           r.size=strlen(r.adr);
  942.           r.soc=INVALID_SOCKET;
  943.           strcpybuff(r.contenttype,"text/html");
  944.         /*} else if (opt.maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  945.           // charger le fichier en mΘmoire tout bΩtement
  946.           r=xhttpget(urladr,urlfil);
  947.           //
  948.         */
  949.         } else {    // backing, multiples sockets
  950.           
  951.           
  952.           /*
  953.             **************************************
  954.             Get the next link, waiting for other files, handling external callbacks
  955.           */
  956.           {
  957.             char buff_err_msg[1024];
  958.             htsmoduleStruct str;
  959.             htsmoduleStructExtended stre;
  960.             buff_err_msg[0] = '\0';
  961.             memset(&str, 0, sizeof(str));
  962.             memset(&stre, 0, sizeof(stre));
  963.             /* */
  964.             str.err_msg = buff_err_msg;
  965.             str.filename = savename;
  966.             str.mime = r.contenttype;
  967.             str.url_host = urladr;
  968.             str.url_file = urlfil;
  969.             str.size = (int) r.size;
  970.             /* */
  971.             str.addLink = htsAddLink;
  972.             /* */
  973.             str.liens = liens;
  974.             str.opt = &opt;
  975.             str.back = back;
  976.             str.back_max = back_max;
  977.             str.cache = &cache;
  978.             str.hashptr = hashptr;
  979.             str.numero_passe = numero_passe;
  980.             str.add_tab_alloc = add_tab_alloc;
  981.             /* */
  982.             str.lien_tot_ = &lien_tot;
  983.             str.ptr_ = &ptr;
  984.             str.lien_size_ = &lien_size;
  985.             str.lien_buffer_ = &lien_buffer;
  986.             /* */
  987.             /* */
  988.             stre.r_ = &r;
  989.             /* */
  990.             stre.error_ = &error;
  991.             stre.exit_xh_ = &exit_xh;
  992.             stre.store_errpage_ = &store_errpage;
  993.             /* */
  994.             stre.base = base;
  995.             stre.codebase = codebase;
  996.             /* */
  997.             stre.filters_ = &filters;
  998.             stre.filptr_ = &filptr;
  999.             stre.robots_ = &robots;
  1000.             stre.hash_ = &hash;
  1001.             stre.lien_max_ = &lien_max;
  1002.             /* */
  1003.             stre.makeindex_done_ = &makeindex_done;
  1004.             stre.makeindex_fp_ = &makeindex_fp;
  1005.             stre.makeindex_links_ = &makeindex_links;
  1006.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1007.             /* */
  1008.             stre.template_header_ = template_header;
  1009.             stre.template_body_ = template_body;
  1010.             stre.template_footer_ = template_footer;
  1011.             /* */
  1012.             stre.stat_fragment_ = &stat_fragment;
  1013.             stre.makestat_time = makestat_time;
  1014.             stre.makestat_fp = makestat_fp;
  1015.             stre.makestat_total_ = &makestat_total;
  1016.             stre.makestat_lnk_ = &makestat_lnk;
  1017.             stre.maketrack_fp = maketrack_fp;
  1018.             /* FUNCTION DEPENDANT */
  1019.             stre.loc_ = loc;
  1020.             stre.last_info_shell_ = &last_info_shell;
  1021.             stre.info_shell_ = &info_shell;
  1022.  
  1023.             /* Parse */
  1024.             switch(hts_mirror_wait_for_next_file(&str, &stre)) {
  1025.             case -1:
  1026.               XH_uninit;
  1027.               return -1;
  1028.               break;
  1029.             case 2:
  1030.               // Jump to 'continue'
  1031.               // This is one of the very very rare cases where goto
  1032.               // is acceptable
  1033.               // A supplemental flag and if( ) { } would be really messy
  1034.               goto jump_if_done;
  1035.             }
  1036.             
  1037.           }
  1038.           
  1039.           
  1040.         }
  1041.         // FIN --RECUPERATION LIEN--- 
  1042.         // ------------------------------------------------------------
  1043.         
  1044.         
  1045.         
  1046.       } else {    // lien vide..
  1047.         if (opt.errlog) {
  1048.           fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning, link #%d empty"LF,ptr); test_flush;
  1049.         }         
  1050.         error=1;
  1051.         goto jump_if_done;
  1052.       }  // test si url existe (non vide!)
  1053.       
  1054.  
  1055.  
  1056.       // ---tester taille a posteriori---
  1057.       // tester r.adr
  1058.       if (!error) {
  1059.         // erreur, pas de fichier chargΘ:
  1060.         if ((!r.adr) && (r.is_write==0) 
  1061.           && (r.statuscode!=301) 
  1062.           && (r.statuscode!=302) 
  1063.           && (r.statuscode!=303) 
  1064.           && (r.statuscode!=307) 
  1065.           && (r.statuscode!=412)
  1066.           && (r.statuscode!=416)
  1067.          ) { 
  1068.           // error=1;
  1069.           
  1070.           // peut Ωtre que le fichier Θtait trop gros?
  1071.           if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
  1072.            || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
  1073.             error=0;
  1074.             if (opt.errlog) {
  1075.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  1076.               test_flush;
  1077.             }
  1078.           }
  1079.           // // // error=1;    // ne pas traiter la suite -- euhh si finalement..
  1080.         }
  1081.       }
  1082.       // ---fin tester taille a posteriori---    
  1083.  
  1084.       
  1085.       // -------------------- 
  1086.       // BOGUS MIME TYPE HACK
  1087.       // Check if we have a bogus MIME type
  1088.       // example: 
  1089.       // Content-type="text/html"
  1090.       // and 
  1091.       // Content-disposition="foo.jpg"
  1092.       // --------------------
  1093.       if (!error) {
  1094.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1095.           if (r.adr) {    // Written file
  1096.             if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1097.               || (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )  /* Is real media, .. */
  1098.               ) {
  1099.               if (strnotempty(r.cdispo)) {      // Content-disposition set!
  1100.                 if (ishtml(savename) == 0) {    // Non HTML!!
  1101.                   // patch it!
  1102.                   strcpybuff(r.contenttype,"application/octet-stream");
  1103.                 }
  1104.               }
  1105.             }
  1106.           }
  1107.         }
  1108.         
  1109.         // ------------------------------------
  1110.         // BOGUS MIME TYPE HACK II (the revenge)
  1111.         // Check if we have a bogus MIME type
  1112.         if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1113.           || (may_be_hypertext_mime(r.contenttype, urlfil))  /* Is real media, .. */
  1114.           ) {
  1115.           if ((r.adr) && (r.size)) {
  1116.             unsigned int map[256];
  1117.             int i;
  1118.             unsigned int nspec = 0;
  1119.             map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
  1120.             for(i = 1 ; i < 32 ; i++) {   //  null chars ignored..
  1121.               if (!is_realspace(i) 
  1122.                 && i != 27        /* Damn you ISO2022-xx! */
  1123.                 ) {
  1124.                 nspec += map[i];
  1125.               }
  1126.             }
  1127.             /* On-the-fly UCS2 to ISO-8859-1 conversion (note: UCS2 should never be used on the net) */
  1128.             if (
  1129.               map[0] > r.size/10
  1130.               &&
  1131.               r.size % 2 == 0
  1132.               &&
  1133.               (
  1134.               ( ((unsigned char) r.adr[0]) == 0xff && ((unsigned char) r.adr[1]) == 0xfe)
  1135.               ||
  1136.               ( ((unsigned char) r.adr[0]) == 0xfe && ((unsigned char) r.adr[1]) == 0xff)
  1137.               )
  1138.               ) {
  1139.               int lost=0;
  1140.               int i;
  1141.               int swap = (r.adr[0] == 0xff);
  1142.               for(i = 0 ; i < r.size / 2 - 1 ; i++) {
  1143.                 unsigned int unic = 0;
  1144.                 if (swap)
  1145.                   unic = (r.adr[i*2 + 2] << 8) + r.adr[i*2 + 2 + 1];
  1146.                 else
  1147.                   unic = r.adr[i*2 + 2] + (r.adr[i*2 + 2 + 1] << 8);
  1148.                 if (unic <= 255)
  1149.                   r.adr[i] = (char) unic;
  1150.                 else {
  1151.                   r.adr[i] = '?';
  1152.                   lost++;
  1153.                 }
  1154.               }
  1155.               r.size = r.size / 2 - 1;
  1156.               r.adr[r.size] = '\0';
  1157.  
  1158.               if (opt.errlog) {
  1159.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File %s%s converted from UCS2 to 8-bit, %d characters lost during conversion (better to use UTF-8)"LF, urladr, urlfil, lost);
  1160.                 test_flush;
  1161.               }
  1162.             } else if ((nspec > r.size / 100) && (nspec > 10)) {    // too many special characters
  1163.               strcpybuff(r.contenttype,"application/octet-stream");
  1164.               if (opt.errlog) {
  1165.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
  1166.                 test_flush;
  1167.               }
  1168.             }
  1169.  
  1170.             /* This hack allows to avoid problems with parsing '\0' characters  */
  1171.             for(i = 0 ; i < r.size ; i++) {
  1172.               if (r.adr[i] == '\0') r.adr[i] = ' ';
  1173.             }
  1174.  
  1175.           }
  1176.  
  1177.  
  1178.         }
  1179.       }
  1180.       
  1181.       // -------------------- 
  1182.       // REAL MEDIA HACK
  1183.       // Check if we have to load locally the file
  1184.       // --------------------
  1185.       if (!error) {
  1186.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1187.           if (r.adr==NULL) {    // Written file
  1188.             if (may_be_hypertext_mime(r.contenttype, urlfil)) {   // to parse!
  1189.               LLint sz;
  1190.               sz=fsize(savename);
  1191.               if (sz>0) {   // ok, exists!
  1192.                 if (sz < 8192) {   // ok, small file --> to parse!
  1193.                   FILE* fp=fopen(savename,"rb");
  1194.                   if (fp) {
  1195.                     r.adr=malloct((int)sz + 2);
  1196.                     if (r.adr) {
  1197.                       if (fread(r.adr,1,(INTsys)sz,fp) == sz) {
  1198.                         r.size=sz;
  1199.                       } else {
  1200.                         freet(r.adr);
  1201.                         r.size=0;
  1202.                         r.adr = NULL;
  1203.                         r.statuscode=-1;
  1204.                         strcpybuff(r.msg, ".RAM read error");
  1205.                       }
  1206.                       fclose(fp);
  1207.                       fp=NULL;
  1208.                       // remove (temporary) file!
  1209.                       remove(savename);
  1210.                     }
  1211.                     if (fp)
  1212.                       fclose(fp);
  1213.                   }
  1214.                 }
  1215.               }
  1216.             }
  1217.           }
  1218.         }
  1219.       }
  1220.       // EN OF REAL MEDIA HACK
  1221.       
  1222.  
  1223.       // ---stockage en cache---
  1224.       // stocker dans le cache?
  1225.       /*
  1226.       if (!error) {
  1227.         if (ptr>0) {
  1228.           if (liens[ptr]) {
  1229.             xxcache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
  1230.           } else
  1231.             error=1;
  1232.         }
  1233.       }
  1234.       */
  1235.       // ---fin stockage en cache---
  1236.       
  1237.       
  1238.       
  1239.       /*
  1240.          **************************************
  1241.          Check "Moved permanently" and other similar errors, retrying URLs if necessary and handling
  1242.          redirect pages.
  1243.       */
  1244.       if (!error) {
  1245.         char buff_err_msg[1024];
  1246.         htsmoduleStruct str;
  1247.         htsmoduleStructExtended stre;
  1248.         buff_err_msg[0] = '\0';
  1249.         memset(&str, 0, sizeof(str));
  1250.         memset(&stre, 0, sizeof(stre));
  1251.         /* */
  1252.         str.err_msg = buff_err_msg;
  1253.         str.filename = savename;
  1254.         str.mime = r.contenttype;
  1255.         str.url_host = urladr;
  1256.         str.url_file = urlfil;
  1257.         str.size = (int) r.size;
  1258.         /* */
  1259.         str.addLink = htsAddLink;
  1260.         /* */
  1261.         str.liens = liens;
  1262.         str.opt = &opt;
  1263.         str.back = back;
  1264.         str.back_max = back_max;
  1265.         str.cache = &cache;
  1266.         str.hashptr = hashptr;
  1267.         str.numero_passe = numero_passe;
  1268.         str.add_tab_alloc = add_tab_alloc;
  1269.         /* */
  1270.         str.lien_tot_ = &lien_tot;
  1271.         str.ptr_ = &ptr;
  1272.         str.lien_size_ = &lien_size;
  1273.         str.lien_buffer_ = &lien_buffer;
  1274.         /* */
  1275.         /* */
  1276.         stre.r_ = &r;
  1277.         /* */
  1278.         stre.error_ = &error;
  1279.         stre.exit_xh_ = &exit_xh;
  1280.         stre.store_errpage_ = &store_errpage;
  1281.         /* */
  1282.         stre.base = base;
  1283.         stre.codebase = codebase;
  1284.         /* */
  1285.         stre.filters_ = &filters;
  1286.         stre.filptr_ = &filptr;
  1287.         stre.robots_ = &robots;
  1288.         stre.hash_ = &hash;
  1289.         stre.lien_max_ = &lien_max;
  1290.         /* */
  1291.         stre.makeindex_done_ = &makeindex_done;
  1292.         stre.makeindex_fp_ = &makeindex_fp;
  1293.         stre.makeindex_links_ = &makeindex_links;
  1294.         stre.makeindex_firstlink_ = makeindex_firstlink;
  1295.         /* */
  1296.         stre.template_header_ = template_header;
  1297.         stre.template_body_ = template_body;
  1298.         stre.template_footer_ = template_footer;
  1299.         /* */
  1300.         stre.stat_fragment_ = &stat_fragment;
  1301.         stre.makestat_time = makestat_time;
  1302.         stre.makestat_fp = makestat_fp;
  1303.         stre.makestat_total_ = &makestat_total;
  1304.         stre.makestat_lnk_ = &makestat_lnk;
  1305.         stre.maketrack_fp = maketrack_fp;
  1306.         
  1307.         /* Parse */
  1308.         if (hts_mirror_check_moved(&str, &stre) != 0) {
  1309.           XH_uninit;
  1310.           return -1;
  1311.         }
  1312.         
  1313.       }
  1314.  
  1315.     }  // if !error
  1316.     
  1317.     if (!error) {
  1318. #if DEBUG_SHOWTYPES
  1319.       if (strstr(REG,r.contenttype)==NULL) {
  1320.         strcatbuff(REG,r.contenttype);
  1321.         strcatbuff(REG,"\n");
  1322.         printf("%s\n",r.contenttype);
  1323.         io_flush;
  1324.       }
  1325. #endif
  1326.       
  1327.  
  1328.       // ------------------------------------------------------
  1329.       // ok, fichier chargΘ localement
  1330.       // ------------------------------------------------------
  1331.       
  1332.       // VΘrificateur d'intΘgritΘ
  1333.       #if DEBUG_CHECKINT
  1334.       {
  1335.         int i;
  1336.         for(i=0;i<back_max;i++) {
  1337.           char si[256];
  1338.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1339.           _CHECKINT(&back[i],si)
  1340.         }
  1341.       }
  1342.       #endif
  1343.  
  1344.  
  1345.       /* info: updated */
  1346.       /*
  1347.       if (ptr>0) {
  1348.         // "mis α jour"
  1349.         if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) {    // page modifiΘe
  1350.           if (strnotempty(savename)) {
  1351.             HTS_STAT.stat_updated_files++;
  1352.             if (opt.log!=NULL) {
  1353.               //if ((opt.debug>0) && (opt.log!=NULL)) {
  1354.               fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
  1355.               test_flush;
  1356.             }
  1357.           }
  1358.         } else {
  1359.           if (!store_errpage) {
  1360.             if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1361.               fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
  1362.               test_flush;
  1363.             }
  1364.           }
  1365.         }
  1366.       }
  1367.       */
  1368.       
  1369.       // ------------------------------------------------------
  1370.       // traitement (parsing)
  1371.       // ------------------------------------------------------
  1372.  
  1373.       // traiter
  1374.       if (
  1375.            ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1376.              || (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )  /* Is real media, .. */
  1377.            )
  1378.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1379.         && (r.adr!=NULL)        /* HTML Data exists */
  1380.         && (r.size>0)           /* And not empty */
  1381.         && (!store_errpage)     /* Not an html error page */
  1382.         && (savename[0]!='\0')  /* Output filename exists */
  1383.         ) {    // ne traiter que le html si autorisΘ
  1384.         // -- -- -- --
  1385.         // Parsing HTML
  1386.         if (!error) {
  1387.           /* Info for wrappers */
  1388.           if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1389.             fspc(opt.log,"info"); fprintf(opt.log,"engine: check-html: %s%s"LF,urladr,urlfil);
  1390.           }
  1391.           {
  1392.             char buff_err_msg[1024];
  1393.             htsmoduleStruct str;
  1394.             htsmoduleStructExtended stre;
  1395.             buff_err_msg[0] = '\0';
  1396.             memset(&str, 0, sizeof(str));
  1397.             memset(&stre, 0, sizeof(stre));
  1398.             /* */
  1399.             str.err_msg = buff_err_msg;
  1400.             str.filename = savename;
  1401.             str.mime = r.contenttype;
  1402.             str.url_host = urladr;
  1403.             str.url_file = urlfil;
  1404.             str.size = (int) r.size;
  1405.             /* */
  1406.             str.addLink = htsAddLink;
  1407.             /* */
  1408.             str.liens = liens;
  1409.             str.opt = &opt;
  1410.             str.back = back;
  1411.             str.back_max = back_max;
  1412.             str.cache = &cache;
  1413.             str.hashptr = hashptr;
  1414.             str.numero_passe = numero_passe;
  1415.             str.add_tab_alloc = add_tab_alloc;
  1416.             /* */
  1417.             str.lien_tot_ = &lien_tot;
  1418.             str.ptr_ = &ptr;
  1419.             str.lien_size_ = &lien_size;
  1420.             str.lien_buffer_ = &lien_buffer;
  1421.             /* */
  1422.             /* */
  1423.             stre.r_ = &r;
  1424.             /* */
  1425.             stre.error_ = &error;
  1426.             stre.exit_xh_ = &exit_xh;
  1427.             stre.store_errpage_ = &store_errpage;
  1428.             /* */
  1429.             stre.base = base;
  1430.             stre.codebase = codebase;
  1431.             /* */
  1432.             stre.filters_ = &filters;
  1433.             stre.filptr_ = &filptr;
  1434.             stre.robots_ = &robots;
  1435.             stre.hash_ = &hash;
  1436.             stre.lien_max_ = &lien_max;
  1437.             /* */
  1438.             stre.makeindex_done_ = &makeindex_done;
  1439.             stre.makeindex_fp_ = &makeindex_fp;
  1440.             stre.makeindex_links_ = &makeindex_links;
  1441.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1442.             /* */
  1443.             stre.template_header_ = template_header;
  1444.             stre.template_body_ = template_body;
  1445.             stre.template_footer_ = template_footer;
  1446.             /* */
  1447.             stre.stat_fragment_ = &stat_fragment;
  1448.             stre.makestat_time = makestat_time;
  1449.             stre.makestat_fp = makestat_fp;
  1450.             stre.makestat_total_ = &makestat_total;
  1451.             stre.makestat_lnk_ = &makestat_lnk;
  1452.             stre.maketrack_fp = maketrack_fp;
  1453.             
  1454.             /* Parse */
  1455.             if (htsparse(&str, &stre) != 0) {
  1456.               XH_uninit;
  1457.               return -1;
  1458.             }
  1459.  
  1460.  
  1461.           // I'll have to segment this part
  1462. // #include "htsparse.c"
  1463.  
  1464.  
  1465.           }
  1466.         }
  1467.         // Fin parsing HTML
  1468.         // -- -- -- --
  1469.  
  1470.  
  1471.       }  // si text/html
  1472.       // -- -- --
  1473.       else {    // sauver fichier quelconque
  1474.         // -- -- --
  1475.         // sauver fichier
  1476.  
  1477.  
  1478.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1479.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1480.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1481.             if (store_errpage) {                    // c'est une page d'erreur
  1482.               int create_html_warning=0;
  1483.               int create_gif_warning=0;
  1484.               switch (ishtml(urlfil)) {      /* pas fichier html */
  1485.               case 0:                        /* non html */
  1486.                 {
  1487.                   char buff[256];
  1488.                   guess_httptype(buff,urlfil);
  1489.                   if (strcmp(buff,"image/gif")==0)
  1490.                     create_gif_warning=1;
  1491.                 }
  1492.                 break;
  1493.               case 1:                        /* html */
  1494.                 if (!r.adr) {
  1495.                 }
  1496.                 break;
  1497.               default:                       /* don't know.. */
  1498.                 break;    
  1499.               }
  1500.               /* CrΘer message d'erreur ? */
  1501.               if (create_html_warning) {
  1502.                 char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
  1503.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1504.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
  1505.                   test_flush;
  1506.                 }
  1507.                 if (adr) {
  1508.                   if (r.adr) {
  1509.                     freet(r.adr);
  1510.                     r.adr=NULL;
  1511.                   }
  1512.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  1513.                   r.adr=adr;
  1514.                 }
  1515.               } else if (create_gif_warning) {
  1516.                 char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
  1517.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1518.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
  1519.                   test_flush;
  1520.                 }
  1521.                 if (r.adr) {
  1522.                   freet(r.adr);
  1523.                   r.adr=NULL;
  1524.                 }
  1525.                 memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
  1526.                 r.adr=adr;
  1527.               }
  1528.             }
  1529.           }
  1530.         }
  1531.  
  1532.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  1533.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  1534.             if (r.adr) {
  1535.               int bptr=0;
  1536.               char line[1024];
  1537.               char buff[8192];
  1538.               char infobuff[8192];
  1539.               int record=0;
  1540.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  1541.               //
  1542. #if DEBUG_ROBOTS
  1543.               printf("robots.txt dump:\n%s\n",r.adr);
  1544. #endif
  1545.               do {
  1546.                 char* comm;
  1547.                 int llen;
  1548.                 bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
  1549.                 /* strip comment */
  1550.                 comm=strchr(line, '#');
  1551.                 if (comm != NULL) {
  1552.                   *comm = '\0';
  1553.                 }
  1554.                 /* strip spaces */
  1555.                 llen=strlen(line);
  1556.                 while(llen > 0 && is_realspace(line[llen - 1])) {
  1557.                   line[llen - 1] = '\0';
  1558.                   llen--;
  1559.                 }
  1560.                 if (strfield(line,"user-agent:")) {
  1561.                   char* a;
  1562.                   a=line+11;
  1563.                   while(is_realspace(*a)) a++;    // sauter espace(s)
  1564.                   if ( *a == '*') {
  1565.                     if (record != 2)
  1566.                       record=1;    // c pour nous
  1567.                   } else if (strfield(a,"httrack") || strfield(a,"winhttrack") || strfield(a,"webhttrack")) {
  1568.                     buff[0]='\0';      // re-enregistrer
  1569.                     infobuff[0]='\0';
  1570.                     record=2;          // locked
  1571. #if DEBUG_ROBOTS
  1572.                     printf("explicit disallow for httrack\n");
  1573. #endif
  1574.                   }
  1575.                   else record=0;
  1576.                 } else if (record) {
  1577.                   if (strfield(line,"disallow:")) {
  1578.                     char* a=line+9;
  1579.                     while(is_realspace(*a))
  1580.                       a++;    // sauter espace(s)
  1581.                     if (strnotempty(a)) {
  1582.                       if (strcmp(a,"/") != 0 || opt.robots >= 3) {      /* ignoring disallow: / */
  1583.                         if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
  1584.                           strcatbuff(buff,a);
  1585.                           strcatbuff(buff,"\n");
  1586.                           if ( (strlen(infobuff) + strlen(a) + 8) < sizeof(infobuff)) {
  1587.                             if (strnotempty(infobuff)) strcatbuff(infobuff,", ");
  1588.                             strcatbuff(infobuff,a);
  1589.                           }
  1590.                         }
  1591.                       } else {
  1592.                         if (opt.errlog!=NULL) {
  1593.                           fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  1594.                           test_flush;
  1595.                         }
  1596.                       }
  1597.                     }
  1598.                   }
  1599.                 }
  1600.               } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
  1601.               if (strnotempty(buff)) {
  1602.                 checkrobots_set(&robots,urladr,buff);
  1603.                 if (opt.log!=NULL) {
  1604.                   if (opt.log != opt.errlog) {
  1605.                     fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  1606.                     test_flush;
  1607.                   } 
  1608.                 }
  1609.                 if (opt.errlog!=NULL) {
  1610.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  1611.                   test_flush;
  1612.                 }
  1613.               }
  1614.             }
  1615.           }
  1616.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  1617.           /*
  1618.           if (!ishttperror(r.statuscode))
  1619.             HTS_STAT.stat_files++;
  1620.           HTS_STAT.stat_bytes+=r.size;
  1621.           */
  1622.           //printf("ok......\n");
  1623.         } else {
  1624.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  1625.           // rΘcursion nous en empΩche
  1626.           // Dans ce cas on met un fichier indiquant ce fait
  1627.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  1628.           // fort, on supprimera le readme, et on scannera le fichier html!
  1629.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  1630.           if ( (is_hypertext_mime(r.contenttype, urlfil)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  1631.             char tempo[HTS_URLMAXSIZE*2];
  1632.             FILE* fp;
  1633.             tempo[0]='\0';
  1634.             strcpybuff(tempo,savename);
  1635.             strcatbuff(tempo,".readme");
  1636.             
  1637. #if HTS_DOSNAME
  1638.             // remplacer / par des slash arriΦre
  1639.             {
  1640.               int i=0;
  1641.               while(tempo[i]) {
  1642.                 if (tempo[i]=='/')
  1643.                   tempo[i]='\\';
  1644.                 i++;
  1645.               } 
  1646.             } 
  1647.             // a partir d'ici le slash devient antislash
  1648. #endif
  1649.             
  1650.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  1651.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION"%s"CRLF""CRLF, WHAT_is_available);
  1652.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  1653.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  1654.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  1655.               fprintf(fp,"and to rescan the URL."CRLF);
  1656.               fclose(fp);
  1657. #if HTS_WIN==0
  1658.               chmod(tempo,HTS_ACCESS_FILE);      
  1659. #endif
  1660.               usercommand(&opt,0,NULL,fconv(tempo),"","");
  1661.             }
  1662.             
  1663.             
  1664.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1665.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  1666.               test_flush;
  1667.             }
  1668.           } else {
  1669.             if ((opt.getmode & 2)!=0) {    // ok autorisΘ
  1670.               if ( (opt.debug>1) && (opt.log!=NULL) ) {
  1671.                 fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
  1672.                 test_flush;
  1673.               }
  1674.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  1675.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1676.                 fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  1677.                 test_flush;
  1678.               } 
  1679.               if (r.adr) {
  1680.                 freet(r.adr); r.adr=NULL;
  1681.               }
  1682.             }
  1683.           }
  1684.           
  1685.           //printf("extern=%s\n",r.contenttype);
  1686.  
  1687.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  1688.           if (r.adr) {
  1689.             if (filesave(&opt,r.adr,(int)r.size,savename,urladr,urlfil)!=0) {
  1690.               int fcheck;
  1691.               if ((fcheck=check_fatal_io_errno())) {
  1692.                 exit_xh=-1;   /* fatal error */
  1693.               }
  1694.               if (opt.errlog) {   
  1695.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to save file %s : %s"LF, savename, strerror(errno));
  1696.                 if (fcheck) {
  1697.                   fspc(opt.errlog,"error");
  1698.                   fprintf(opt.errlog,"* * Fatal write error, giving up"LF);
  1699.                 }
  1700.                 test_flush;
  1701.               }
  1702.             } else {
  1703.               /*
  1704.               if (!ishttperror(r.statuscode))
  1705.                 HTS_STAT.stat_files++;
  1706.               HTS_STAT.stat_bytes+=r.size;
  1707.               */
  1708.             }
  1709.           }
  1710.           
  1711.         }
  1712.   
  1713.  
  1714.         /* Parsing of other media types (java, ram..) */
  1715.         /*
  1716.         if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
  1717.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1718.             fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush;
  1719.           }
  1720.           if (fexist(savename)) {   // ok, existe bien!
  1721.             FILE* fp=fopen(savename,"r+b");
  1722.             if (fp) {
  1723.               if (!fseek(fp,0,SEEK_SET)) {
  1724.                 char line[HTS_URLMAXSIZE*2];
  1725.                 linput(fp,line,HTS_URLMAXSIZE);
  1726.                 if (strnotempty(line)) {
  1727.                   if ((opt.debug>1) && (opt.log!=NULL)) {
  1728.                     fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush;
  1729.                   }
  1730.                 }
  1731.               }
  1732.               fclose(fp);
  1733.             }
  1734.           }
  1735.         } else */
  1736.  
  1737.  
  1738.         /* External modules */
  1739.         if (opt.parsejava && fexist(savename)) {
  1740.           char buff_err_msg[1024];
  1741.           htsmoduleStruct str;
  1742.           buff_err_msg[0] = '\0';
  1743.           memset(&str, 0, sizeof(str));
  1744.           /* */
  1745.           str.err_msg = buff_err_msg;
  1746.           str.filename = savename;
  1747.           str.mime = r.contenttype;
  1748.           str.url_host = urladr;
  1749.           str.url_file = urlfil;
  1750.           str.size = (int) r.size;
  1751.           /* */
  1752.           str.addLink = htsAddLink;
  1753.           /* */
  1754.           str.liens = liens;
  1755.           str.opt = &opt;
  1756.           str.back = back;
  1757.           str.back_max = back_max;
  1758.           str.cache = &cache;
  1759.           str.hashptr = hashptr;
  1760.           str.numero_passe = numero_passe;
  1761.           str.add_tab_alloc = add_tab_alloc;
  1762.           /* */
  1763.           str.lien_tot_ = &lien_tot;
  1764.           str.ptr_ = &ptr;
  1765.           str.lien_size_ = &lien_size;
  1766.           str.lien_buffer_ = &lien_buffer;
  1767.           /* Parse if recognized */
  1768.           switch(hts_parse_externals(&str)) {
  1769.           case 1:
  1770.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1771.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): parsed successfully %s"LF,savename); test_flush;
  1772.             }
  1773.             break;
  1774.           case 0:
  1775.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1776.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): couldn't parse successfully %s : %s"LF,savename, str.err_msg); test_flush;
  1777.             }
  1778.             break;
  1779.           }
  1780.         }
  1781.              
  1782.         
  1783.       }  // text/html ou autre
  1784.       
  1785.  
  1786.       /* Post-processing */
  1787.       if (fexist(savename)) {
  1788.         usercommand(&opt, 0, NULL, savename, urladr, urlfil);
  1789.       }
  1790.  
  1791.  
  1792.     }  // if !error
  1793.     
  1794.  
  1795. jump_if_done:
  1796.     // libΘrer les liens
  1797.     if (r.adr) { 
  1798.       freet(r.adr); 
  1799.       r.adr=NULL; 
  1800.     }   // libΘrer la mΘmoire!
  1801.     
  1802.     // prochain lien
  1803.     ptr++;
  1804.     
  1805.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  1806.     if (opt.getmode & 4) {    // sauver les non html aprΦs
  1807.       // sauter les fichiers selon la passe
  1808.       if (!numero_passe) {
  1809.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  1810.       } else {
  1811.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  1812.       }
  1813.       if (ptr>=lien_tot) {     // fin de boucle
  1814.         if (!numero_passe) { // premiΦre boucle
  1815.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1816.             fprintf(opt.log,LF"Now getting non-html files..."LF);
  1817.             test_flush;
  1818.           }
  1819.           numero_passe=1;   // seconde boucle
  1820.           ptr=0;
  1821.           // prochain pass2
  1822.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  1823.           
  1824.           //printf("first link==%d\n");
  1825.           
  1826.         }
  1827.       }  
  1828.     }
  1829.  
  1830.     // copy abort state if necessary from outside
  1831.     if (!exit_xh && opt.state.exit_xh) {
  1832.       exit_xh=opt.state.exit_xh;
  1833.     }
  1834.     // a-t-on dΘpassΘ le quota?
  1835.     if (!back_checkmirror(&opt)) {
  1836.       ptr=lien_tot;
  1837.     } else if (exit_xh) {  // sortir
  1838.       if (opt.errlog) {
  1839.         fspc(opt.errlog,"info"); 
  1840.         if (exit_xh==1) {
  1841.           fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1842.         } else {
  1843.           fprintf(opt.errlog,"Exit requested by engine"LF);
  1844.         }
  1845.         test_flush;
  1846.       } 
  1847.       ptr=lien_tot;
  1848.     }
  1849.   } while(ptr<lien_tot);
  1850.   //
  1851.   //
  1852.   //
  1853.   
  1854.   /*
  1855.   Ensure the index is being closed
  1856.   */
  1857.   HT_INDEX_END;
  1858.   
  1859.   /* 
  1860.     updating-a-remotely-deteted-website hack
  1861.     no much data transfered, no data saved
  1862.     <no files successfulyl saved>
  1863.     we assume that something was bad (no connection)
  1864.     just backup old cache and restore everything
  1865.   */
  1866.   if (
  1867.     (HTS_STAT.stat_files <= 0) 
  1868.     && 
  1869.     (HTS_STAT.HTS_TOTAL_RECV < 32768)    /* should be fine */
  1870.     ) {
  1871.     if (opt.errlog) {
  1872.       fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  1873.       test_flush;
  1874.     } 
  1875.     XH_uninit;
  1876.     if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
  1877.       remove(fconcat(opt.path_log,"hts-cache/new.dat"));
  1878.       remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
  1879.       remove(fconcat(opt.path_log,"hts-cache/new.lst"));
  1880.       remove(fconcat(opt.path_log,"hts-cache/new.txt"));
  1881.       rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
  1882.       rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
  1883.       rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
  1884.       rename(fconcat(opt.path_log,"hts-cache/old.txt"),fconcat(opt.path_log,"hts-cache/new.txt"));
  1885.     }
  1886.     exit_xh=2;        /* interrupted (no connection detected) */
  1887.     return 1;
  1888.   }
  1889.  
  1890.   // info text  
  1891.   if (cache.txt) {
  1892.     fclose(cache.txt); cache.txt=NULL;
  1893.   }
  1894.  
  1895.   // purger!
  1896.   if (cache.lst) {
  1897.     fclose(cache.lst); cache.lst=NULL;
  1898.     if (opt.delete_old) {
  1899.       FILE *old_lst,*new_lst;
  1900.       //
  1901. #if HTS_ANALYSTE
  1902.       _hts_in_html_parsing=3;
  1903. #endif
  1904.       //
  1905.       old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
  1906.       if (old_lst) {
  1907.         LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
  1908.         new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
  1909.         if ((new_lst) && (sz>0)) {
  1910.           char* adr=(char*) malloct((INTsys)sz);
  1911.           if (adr) {
  1912.             if (fread(adr,1,(INTsys)sz,new_lst) == sz) {
  1913.               char line[1100];
  1914.               int purge=0;
  1915.               while(!feof(old_lst)) {
  1916.                 linput(old_lst,line,1000);
  1917.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  1918.                   char file[HTS_URLMAXSIZE*2];
  1919.                   strcpybuff(file,opt.path_html);
  1920.                   strcatbuff(file,line+1);
  1921.                   file[strlen(file)-1]='\0';
  1922.                   if (fexist(file)) {       // toujours sur disque: virer
  1923.                     if (opt.log) {
  1924.                       fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
  1925.                     }
  1926.                     remove(file); purge=1;
  1927.                   }
  1928.                 }
  1929.               }
  1930.               {
  1931.                 fseek(old_lst,0,SEEK_SET);
  1932.                 while(!feof(old_lst)) {
  1933.                   linput(old_lst,line,1000);
  1934.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  1935.                     line[strlen(line)-1]='\0';
  1936.                   }
  1937.                   if (strnotempty(line))
  1938.                     line[strlen(line)-1]='\0';
  1939.                   if (strnotempty(line))
  1940.                     if (!strstr(adr,line)) {    // non trouvΘ?
  1941.                       char file[HTS_URLMAXSIZE*2];
  1942.                       strcpybuff(file,opt.path_html);
  1943.                       strcatbuff(file,line+1);
  1944.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  1945.                         purge=1;
  1946.                         if (opt.log) {
  1947.                           fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
  1948.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  1949.                             file[strlen(file)-1]='\0';
  1950.                           }
  1951.                           if (strnotempty(file))
  1952.                             file[strlen(file)-1]='\0';
  1953.                         }
  1954.                       }
  1955.                     }
  1956.                 }
  1957.               }
  1958.               //
  1959.               if (!purge) {
  1960.                 if (opt.log) {
  1961.                   fprintf(opt.log,"No files purged"LF);
  1962.                 }
  1963.               }
  1964.             }
  1965.             freet(adr);
  1966.           }
  1967.           fclose(new_lst);
  1968.         }
  1969.         fclose(old_lst);
  1970.       }
  1971.       //
  1972. #if HTS_ANALYSTE
  1973.       _hts_in_html_parsing=0;
  1974. #endif
  1975.     }
  1976.   }
  1977.   // fin purge!
  1978.  
  1979.   // Indexation
  1980.   if (opt.kindex)
  1981.     index_finish(opt.path_html,opt.kindex);
  1982.  
  1983.   // afficher rΘsumΘ dans log
  1984.   if (opt.log!=NULL) {
  1985.     char finalInfo[8192];
  1986.     int error   = fspc(NULL,"error");
  1987.     int warning = fspc(NULL,"warning");
  1988.     int info    = fspc(NULL,"info");
  1989.     char htstime[256];
  1990.     char infoupdated[256];
  1991.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  1992.     LLint n=(LLint) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
  1993.     
  1994.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  1995.     //sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  1996.     infoupdated[0] = '\0';
  1997.     if (opt.is_update) {
  1998.       if (HTS_STAT.stat_updated_files < 0) {
  1999.         sprintf(infoupdated, ", %d files updated", (int)HTS_STAT.stat_updated_files);
  2000.       } else {
  2001.         sprintf(infoupdated, ", no files updated");
  2002.       }
  2003.     }
  2004.     finalInfo[0] = '\0';
  2005.     sprintf(finalInfo + strlen(finalInfo),
  2006.       "HTTrack Website Copier/"HTTRACK_VERSION" mirror complete in %s : "
  2007.       "%d links scanned, %d files written ("LLintP" bytes overall)%s "
  2008.       "["LLintP" bytes received at "LLintP" bytes/sec]",
  2009.       htstime,
  2010.       (int)lien_tot-1,
  2011.       (int)HTS_STAT.stat_files,
  2012.       (LLint)HTS_STAT.stat_bytes,
  2013.       infoupdated,
  2014.       (LLint)HTS_STAT.HTS_TOTAL_RECV,
  2015.       (LLint)n
  2016.       );
  2017.  
  2018.     if (HTS_STAT.total_packed > 0 && HTS_STAT.total_unpacked > 0) {
  2019.       int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
  2020.       sprintf(finalInfo + strlen(finalInfo),", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",(LLint)HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,(int)packed_ratio);
  2021.     }
  2022.     if (!opt.nokeepalive && HTS_STAT.stat_sockid > 0 && HTS_STAT.stat_nrequests > HTS_STAT.stat_sockid) {
  2023.       int rq = (HTS_STAT.stat_nrequests * 10) / HTS_STAT.stat_sockid;
  2024.       sprintf(finalInfo + strlen(finalInfo),", %d.%d requests per connection", rq/10, rq%10);
  2025.     }
  2026.     sprintf(finalInfo + strlen(finalInfo),LF);
  2027.     if (error)
  2028.       sprintf(finalInfo + strlen(finalInfo),"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2029.     else
  2030.       sprintf(finalInfo + strlen(finalInfo),"(No errors, %d warnings, %d messages)"LF,warning,info);
  2031.  
  2032.     // Log
  2033.     fprintf(opt.log,LF"%s", finalInfo);
  2034.  
  2035.     // Close ZIP
  2036.     if (cache.zipOutput) {
  2037.       zipClose(cache.zipOutput, finalInfo);
  2038.       cache.zipOutput = NULL;
  2039.     }
  2040.     
  2041.     test_flush;
  2042.   }
  2043. #if DEBUG_HASH
  2044.   // noter les collisions
  2045.   {
  2046.     int i;
  2047.     int empty1=0,empty2=0,empty3=0;
  2048.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2049.       if (hash.hash[0][i] == -1)
  2050.         empty1++;
  2051.       if (hash.hash[1][i] == -1)
  2052.         empty2++;
  2053.       if (hash.hash[2][i] == -1)
  2054.         empty3++;
  2055.     }
  2056.     printf("\n");
  2057.     printf("Debug info: Hash-table report\n");
  2058.     printf("Number of files entered:   %d\n",hashnumber);
  2059.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2060.     printf("\n");
  2061.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2062.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2063.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2064.     printf("\n");
  2065.   }
  2066. #endif    
  2067.   // fin afficher rΘsumΘ dans log
  2068.  
  2069.   // ending
  2070.   usercommand(&opt,0,NULL,NULL,NULL,NULL);
  2071.  
  2072.   // dΘsallocation mΘmoire & buffers
  2073.   XH_uninit;
  2074.  
  2075.   return 1;    // OK
  2076. }
  2077. // version 2 pour le reste
  2078. // flusher si on doit lire peu α peu le fichier
  2079. #undef test_flush
  2080. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  2081.  
  2082.  
  2083. // Estimate transfer rate
  2084. // a little bit complex, but not too much
  2085. /*
  2086.   .. : idle
  2087.   ^  : event
  2088.  
  2089.   ----|----|----|----|----|----|----|----|---->
  2090.    1    2    3    4    5    6    7    8    9   time (seconds)
  2091.   ----|----|----|----|----|----|----|----|---->
  2092.   ^........^.........^.........^.........^.... timer 0
  2093.   ----^.........^.........^.........^......... timer 1
  2094.            0    1    0    1    0    1    0     timer N sets its statistics
  2095.       *         *         *         *          timer 0 resync timer 1
  2096.  
  2097.   Therefore, each seconds, we resync the transfer rate with 2-seconds
  2098.  
  2099. */
  2100. int engine_stats(void) {
  2101. #if 0
  2102.   static FILE* debug_fp=NULL; /* ok */
  2103.   if (!debug_fp)
  2104.     debug_fp=fopen("esstat.txt","wb");
  2105. #endif
  2106.   HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk==0;
  2107.   HTS_STAT.nb=0;
  2108.   if (HTS_STAT.HTS_TOTAL_RECV>2048) {
  2109.     TStamp cdif=mtime_local();
  2110.     int i;
  2111.  
  2112.     for(i=0;i<2;i++) {
  2113.       if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
  2114.         TStamp dif;
  2115. #if 0
  2116. fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
  2117. #endif
  2118.         dif=cdif - HTS_STAT.istat_timestart[i];
  2119.         if ((TStamp)(dif/1000)>0) {
  2120.           LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
  2121.           HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
  2122.           HTS_STAT.istat_idlasttimer=i;      // this timer recently sets the stats
  2123.           //
  2124.           HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
  2125.           HTS_STAT.istat_timestart[i]=cdif;
  2126.         }
  2127.         return 1;       /* refreshed */
  2128.       }
  2129.     }
  2130.  
  2131.     // resynchronization between timer 0 (master) and 1 (slave)
  2132.     // timer #0 resync timer #1 when reaching 1 second limit
  2133.     if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
  2134.       if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
  2135. #if 0
  2136. fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
  2137. #endif
  2138.         HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
  2139.         HTS_STAT.istat_timestart[1]=cdif;
  2140.         HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
  2141.       }
  2142.     }
  2143.  
  2144.   }
  2145.   return 0;
  2146. }
  2147.  
  2148.  
  2149. #define _FILTERS     (*opt->filters.filters)
  2150. #define _FILTERS_PTR (opt->filters.filptr)
  2151. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  2152.  
  2153. // bannir host (trop lent etc)
  2154. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,lien_back* back,int back_max,char* host) {
  2155.   //int l;
  2156.   int i;
  2157.  
  2158.   if (host[0]=='!')
  2159.     return;    // erreur.. dΘja cancellΘ.. bizarre.. devrait pas arriver
  2160.  
  2161.   /* sanity check */
  2162.   if (*_FILTERS_PTR + 1 >= opt->maxfilter) {
  2163.     opt->maxfilter += HTS_FILTERSINC;
  2164.     if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  2165.       printf("PANIC! : Too many filters : >%d [%d]\n",*_FILTERS_PTR,__LINE__);
  2166.       if (opt->errlog) {
  2167.         fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF,*_FILTERS_PTR);
  2168.         fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  2169.         fflush(opt->errlog);
  2170.       }
  2171.       assertf("too many filters - giving up" == NULL);
  2172.     }
  2173.   }
  2174.  
  2175.   // interdire host
  2176.   assertf((*_FILTERS_PTR) < opt->maxfilter);
  2177.   if (*_FILTERS_PTR < opt->maxfilter) {
  2178.     strcpybuff(_FILTERS[*_FILTERS_PTR],"-");
  2179.     strcatbuff(_FILTERS[*_FILTERS_PTR],host);
  2180.     strcatbuff(_FILTERS[*_FILTERS_PTR],"/*");     // host/ * interdit
  2181.     (*_FILTERS_PTR)++; 
  2182.   }
  2183.   
  2184.   // oups
  2185.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2186.     if (strcmp(host,"file://")) {
  2187.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2188.       if (opt->log!=NULL) {
  2189.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2190.       }          
  2191.       return;  // purΘe
  2192.     }
  2193.   }
  2194.   
  2195.   // couper connexion
  2196.   for(i=0;i<back_max;i++) {
  2197.     if (back[i].status>=0)    // rΘception OU prΩt
  2198.       if (strfield2(back[i].url_adr,host)) {
  2199. #if HTS_DEBUG_CLOSESOCK
  2200.         DEBUG_W("host control: deletehttp\n");
  2201. #endif
  2202.         back[i].status=0;  // terminΘ
  2203.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2204.         back[i].r.soc=INVALID_SOCKET;
  2205.         back[i].r.statuscode=-2;    // timeout (peu importe si c'est un traffic jam)
  2206.         strcpybuff(back[i].r.msg,"Link Cancelled by host control");
  2207.         
  2208.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2209.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2210.         }          
  2211.       }
  2212.   }
  2213.   
  2214.   // effacer liens
  2215.   //l=strlen(host);
  2216.   for(i=0;i<lien_tot;i++) {
  2217.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2218.     // Calcul de taille sΘcurisΘe
  2219.     if (liens[i]) {
  2220.       if (liens[i]->adr) {
  2221.         int l = 0;
  2222.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2223.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2224.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2225.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2226.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2227.             }
  2228.             strcpybuff(liens[i]->adr,"!");    // cancel (invalide hash)
  2229. #if HTS_HASH
  2230. #else
  2231.             liens[i]->sav_len=-1;         // taille invalide
  2232. #endif
  2233.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2234.           }
  2235.         } else {
  2236.           if (opt->log!=NULL) {
  2237.             char dmp[1040];
  2238.             dmp[0]='\0';
  2239.             strncatbuff(dmp,liens[i]->adr,1024);
  2240.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2241.             fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
  2242.           }          
  2243.         }
  2244.       } else {
  2245.         if (opt->log!=NULL) {
  2246.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2247.         }  
  2248.       }
  2249.     } else {
  2250.       if (opt->log!=NULL) {
  2251.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2252.       }  
  2253.     }
  2254.     //}
  2255.   }
  2256. }
  2257.  
  2258.  
  2259. #if 0
  2260. /* Init structure */
  2261. /* 1 : init */
  2262. /* -1 : off */
  2263. /* 0 : query */
  2264. /* 2 : LOCK */
  2265. /* -2 : UNLOCK */
  2266. void* structcheck_init(int init) {
  2267.   int structcheck_size = 1024;
  2268.   inthash structcheck_hash=NULL;
  2269.   /* */
  2270.   static PTHREAD_LOCK_TYPE structcheck_init_mutex;
  2271.   static int structcheck_init_mutex_init=0;
  2272.  
  2273.   if (init == 1 || init == -1) {
  2274.     if (init) {
  2275.       if (structcheck_hash)
  2276.         inthash_delete(&structcheck_hash);
  2277.       structcheck_hash=NULL;
  2278.     }
  2279.     if (init != -1) {
  2280.       if (structcheck_init_mutex_init == 0) {
  2281.         htsSetLock(&structcheck_init_mutex, -999);
  2282.         structcheck_init_mutex_init=1;
  2283.       }
  2284.       if (structcheck_hash==NULL) {
  2285.         structcheck_hash=inthash_new(structcheck_size);  // dΘsallouΘ xh_xx
  2286.       }
  2287.     }
  2288.   }
  2289.  
  2290.   /* Lock / Unlock */
  2291.   if (init == 2) {  // Lock
  2292.     htsSetLock(&structcheck_init_mutex, 1);
  2293.   } else if (init == -2) {  // Unlock
  2294.     htsSetLock(&structcheck_init_mutex, 0);
  2295.   }
  2296.   return structcheck_hash;
  2297. }
  2298. #endif
  2299.  
  2300. int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
  2301.   char** filters = *ptrfilters;
  2302.   int filter_max=maximum(maxfilter, 128);
  2303.   if (filters == NULL) {
  2304.     filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
  2305.     memset(filters, 0, sizeof(char*) * (filter_max+2));  // filters[0] == 0
  2306.   } else {
  2307.     filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
  2308.   }
  2309.   if (filters) {
  2310.     if (filters[0] == NULL) {
  2311.       filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2312.       memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2313.     } else {
  2314.       filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2315.     }
  2316.     if (filters[0] == NULL) {
  2317.       freet(filters);
  2318.       filters = NULL;
  2319.     }
  2320.   }
  2321.   if (filters != NULL) {
  2322.     int i;
  2323.     int from;
  2324.     if (filterinc == 0)
  2325.       from = 0;
  2326.     else
  2327.       from = filter_max - filterinc;
  2328.     for(i=0 ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2329.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  2330.     }
  2331.     for(i=from ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2332.       filters[i][0]='\0';    // clear
  2333.     }
  2334.   }
  2335.   *ptrfilters = filters;
  2336.   return (filters != NULL) ? filter_max : 0;
  2337. }
  2338.  
  2339. // vΘrifier prΘsence de l'arbo
  2340. HTSEXT_API int structcheck(char* s) {
  2341.   // vΘrifier la prΘsence des dossier(s)
  2342.   char *a=s;
  2343.   char nom[HTS_URLMAXSIZE*2];
  2344.   char *b;
  2345.   //inthash structcheck_hash=NULL;
  2346.   if (strnotempty(s)==0) return 0;
  2347.   if (strlen(s)>HTS_URLMAXSIZE) return 0;
  2348.  
  2349.   // Get buffer address
  2350.   /*
  2351.   structcheck_hash = (inthash)structcheck_init(0);
  2352.   if (structcheck_hash == NULL) {
  2353.     return -1;
  2354.   }
  2355.   */
  2356.  
  2357.   b=nom;
  2358.   do {    
  2359.     if (*a) *b++=*a++;
  2360.     while((*a!='/') && (*a!='\0')) *b++=*a++;
  2361.     *b='\0';    // pas de ++ pour boucler
  2362.     if (*a=='/') {    // toujours dossier
  2363.       if (strnotempty(nom)) {         
  2364.         //if (inthash_write(structcheck_hash, nom, 1)) {    // non encore crΘΘ                       
  2365. #if HTS_WIN
  2366.         if (mkdir(fconv(nom))!=0)
  2367. #else    
  2368.           if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
  2369. #endif
  2370.           {
  2371. #if HTS_REMOVE_ANNOYING_INDEX
  2372.             // might be a filename with same name than this folder
  2373.             // then, remove it to allow folder creation
  2374.             // it happends when servers gives a folder index while
  2375.             // requesting / page
  2376.             // -> if the file can be opened (not a folder) then rename it
  2377.             if (fexist(fconv(nom))) {
  2378.               rename(fconv(nom),fconcat(fconv(nom),".txt"));
  2379.             }
  2380.             // if it fails, that's too bad
  2381. #if HTS_WIN
  2382.             mkdir(fconv(nom));
  2383. #else    
  2384.             mkdir(fconv(nom),HTS_ACCESS_FOLDER);
  2385. #endif
  2386. #endif
  2387.             // Si existe dΘja renvoie une erreur.. tant pis
  2388.           }
  2389. #if HTS_WIN==0
  2390.           /*chmod(fconv(nom),HTS_ACCESS_FOLDER);*/
  2391. #endif
  2392.           //}
  2393.       }
  2394.       *b++=*a++;    // slash
  2395.     } 
  2396.   } while(*a);
  2397.   return 0;
  2398. }
  2399.  
  2400.  
  2401. // sauver un fichier
  2402. int filesave(httrackp* opt,char* adr,int len,char* s,char* url_adr,char* url_fil) {
  2403.   FILE* fp;
  2404.   // Θcrire le fichier
  2405.   if ((fp=filecreate(s))!=NULL) {
  2406.     int nl=0;
  2407.     if (len>0) {
  2408.       nl=(int) fwrite(adr,1,(INTsys)len,fp);
  2409.     }
  2410.     fclose(fp);
  2411.     //xxusercommand(opt,0,NULL,fconv(s),url_adr,url_fil);
  2412.     if (nl!=len)  // erreur
  2413.       return -1;
  2414.   } else
  2415.     return -1;
  2416.   
  2417.   return 0;
  2418. }
  2419.  
  2420. /* We should stop */
  2421. int check_fatal_io_errno(void) {
  2422.   switch(errno) {
  2423. #ifdef EMFILE
  2424.   case EMFILE: /* Too many open files */
  2425. #endif
  2426. #ifdef ENOSPC
  2427.   case ENOSPC: /* No space left on device */
  2428. #endif
  2429. #ifdef EROFS
  2430.   case EROFS:  /* Read-only file system */
  2431. #endif
  2432.     return 1;
  2433.     break;
  2434.   }
  2435.   return 0;
  2436. }
  2437.  
  2438.  
  2439. // ouvrir un fichier (avec chemin Un*x)
  2440. FILE* filecreate(char* s) {
  2441.   char fname[HTS_URLMAXSIZE*2];
  2442.   FILE* fp;
  2443.   fname[0]='\0';
  2444.  
  2445.   // noter lst
  2446.   filenote(s,NULL);
  2447.   
  2448.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2449.   strcpybuff(fname,s);
  2450.  
  2451. #if HTS_DOSNAME
  2452.   // remplacer / par des slash arriΦre
  2453.   {
  2454.     int i=0;
  2455.     while(fname[i]) {
  2456.       if (fname[i]=='/')
  2457.         fname[i]='\\';
  2458.       i++;
  2459.     } 
  2460.   } 
  2461.   // a partir d'ici le slash devient antislash
  2462. #endif
  2463.   
  2464.   // ouvrir
  2465.   fp=fopen(fname,"wb");
  2466.   if (fp == NULL) {
  2467.     // construire le chemin si besoin est
  2468.     (void)structcheck(s);
  2469.     fp=fopen(fname,"wb");
  2470.   }
  2471.   
  2472. #if HTS_WIN==0
  2473.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2474. #endif
  2475.  
  2476.   return fp;
  2477. }
  2478.  
  2479. // create an empty file
  2480. int filecreateempty(char* filename) {
  2481.   FILE* fp;
  2482.   fp=filecreate(filename);      // filenote & co
  2483.   if (fp) {
  2484.     fclose(fp);
  2485.     return 1;
  2486.   } else
  2487.     return 0; 
  2488. }
  2489.  
  2490. // noter fichier
  2491. typedef struct {
  2492.   FILE* lst;
  2493.   char path[HTS_URLMAXSIZE*2];
  2494. } filenote_strc;
  2495. int filenote(char* s,filecreate_params* params) {
  2496.   filenote_strc* strc;
  2497.   NOSTATIC_RESERVE(strc, filenote_strc, 1);
  2498.   
  2499.   // gestion du fichier liste liste
  2500.   if (params) {
  2501.     //filecreate_params* p = (filecreate_params*) params;
  2502.     strcpybuff(strc->path,params->path);
  2503.     strc->lst=params->lst;
  2504.     return 0;
  2505.   } else if (strc->lst) {
  2506.     char savelst[HTS_URLMAXSIZE*2];
  2507.     strcpybuff(savelst,fslash(s));
  2508.     // couper chemin?
  2509.     if (strnotempty(strc->path)) {
  2510.       if (strncmp(fslash(strc->path),savelst,strlen(strc->path))==0) {  // couper
  2511.         strcpybuff(savelst,s+strlen(strc->path));
  2512.       }
  2513.     }
  2514.     fprintf(strc->lst,"[%s]"LF,savelst);
  2515.     fflush(strc->lst);
  2516.   }
  2517.   return 1;
  2518. }
  2519.  
  2520. // executer commande utilisateur
  2521. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil);
  2522. typedef struct {
  2523.   int exe;
  2524.   char cmd[2048];
  2525. } usercommand_strc;
  2526. HTS_INLINE void usercommand(httrackp* opt,int _exe,char* _cmd,char* file,char* adr,char* fil) {
  2527.   usercommand_strc* strc;
  2528.   NOSTATIC_RESERVE(strc, usercommand_strc, 1);
  2529.   
  2530.   /* Callback */
  2531.   if (_exe) {
  2532.     strcpybuff(strc->cmd,_cmd);
  2533.     if (strnotempty(strc->cmd))
  2534.       strc->exe=_exe;
  2535.     else
  2536.       strc->exe=0;
  2537.   }
  2538.  
  2539.   /* post-processing */
  2540.   postprocess_file(opt, file, adr, fil);
  2541.  
  2542. #if HTS_ANALYSTE
  2543.   if (hts_htmlcheck_filesave != NULL)
  2544.   if (file != NULL && strnotempty(file))
  2545.     hts_htmlcheck_filesave(file);
  2546. #endif
  2547.  
  2548.   if (strc->exe) {
  2549.     if (file != NULL && strnotempty(file)) {
  2550.       if (strnotempty(strc->cmd)) {
  2551.         usercommand_exe(strc->cmd,file);
  2552.       }
  2553.     }
  2554.   }
  2555. }
  2556. void usercommand_exe(char* cmd,char* file) {
  2557.   char temp[8192];
  2558.   char c[2]="";
  2559.   int i;
  2560.   temp[0]='\0';
  2561.   //
  2562.   for(i=0;i<(int) strlen(cmd);i++) {
  2563.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2564.       strcatbuff(temp,file);
  2565.       i++;
  2566.     } else {
  2567.       c[0]=cmd[i]; c[1]='\0';
  2568.       strcatbuff(temp,c);
  2569.     }
  2570.   }
  2571.   system(temp);
  2572. }
  2573.  
  2574.  
  2575. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil) {
  2576.   int first = 0;
  2577.   /* MIME-html archive to build */
  2578.   if (opt != NULL && opt->mimehtml) {
  2579.     if (adr != NULL && strcmp(adr, "primary") == 0) {
  2580.       adr = NULL;
  2581.     }
  2582.     if (save != NULL && opt != NULL && adr != NULL && adr[0] && strnotempty(save) && fexist(save)) {
  2583.       char* rsc_save = save;
  2584.       char* rsc_fil = strrchr(fil, '/');
  2585.       int n;
  2586.       if (rsc_fil == NULL)
  2587.         rsc_fil = fil;
  2588.       if (strncmp(fslash(save), fslash(opt->path_html), (n = (int)strlen(opt->path_html))) == 0) {
  2589.         rsc_save += n;
  2590.       }
  2591.  
  2592.       if (!opt->state.mimehtml_created) {
  2593.         first = 1;
  2594.         opt->state.mimefp = fopen(fconcat(opt->path_html,"index.mht"), "wb");
  2595.         if (opt->state.mimefp != NULL) {
  2596.           char rndtmp[1024], currtime[256];
  2597.           srand(time(NULL));
  2598.           time_gmt_rfc822(currtime);
  2599.           sprintf(rndtmp, "%d_%d", (int)time(NULL), (int) rand());
  2600.           sprintf(opt->state.mimemid, "----=_MIMEPart_%s_=----", rndtmp);
  2601.           fprintf(opt->state.mimefp, "From: HTTrack Website Copier <nobody@localhost>\r\n"
  2602.             "Subject: Local mirror\r\n"
  2603.             "Date: %s\r\n"
  2604.             "Message-ID: <httrack_%s@localhost>\r\n"
  2605.             "Content-Type: multipart/related;\r\n"
  2606.             "\tboundary=\"%s\";\r\n"
  2607.             "\ttype=\"text/html\"\r\n"
  2608.             "MIME-Version: 1.0\r\n"
  2609.             "\r\nThis message is a RFC MIME-compliant multipart message.\r\n"
  2610.             "\r\n"
  2611.             , currtime, rndtmp, opt->state.mimemid);
  2612.           opt->state.mimehtml_created = 1;
  2613.         } else {
  2614.           opt->state.mimehtml_created = -1;
  2615.           if ( opt->errlog != NULL ) {
  2616.             fspc(opt->errlog,"error"); fprintf(opt->log,"unable to create index.mht"LF);
  2617.           }
  2618.         }
  2619.       }
  2620.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2621.         FILE* fp = fopen(save, "rb");
  2622.         if (fp != NULL) {
  2623.           char buff[60*100 + 2];
  2624.           char mimebuff[256];
  2625.           char cid[HTS_URLMAXSIZE*3];
  2626.           int len;
  2627.           int isHtml = ( ishtml(save) == 1 );
  2628.           mimebuff[0] = '\0';
  2629.  
  2630.           /* CID */
  2631.           strcpybuff(cid, adr);
  2632.           strcatbuff(cid, fil);
  2633.           escape_in_url(cid);
  2634.           { char* a = cid; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2635.           
  2636.           guess_httptype(mimebuff, save);
  2637.           fprintf(opt->state.mimefp, "--%s\r\n", opt->state.mimemid);
  2638.           /*if (first)
  2639.           fprintf(opt->state.mimefp, "Content-disposition: inline\r\n");
  2640.           else*/
  2641.           fprintf(opt->state.mimefp, "Content-disposition: attachment; filename=\"%s\"\r\n", rsc_save);
  2642.           fprintf(opt->state.mimefp, 
  2643.             "Content-Type: %s\r\n"
  2644.             "Content-Transfer-Encoding: %s\r\n"
  2645.             /*"Content-Location: http://localhost/%s\r\n"*/
  2646.             "Content-ID: <%s>\r\n"
  2647.             "\r\n"
  2648.             , mimebuff
  2649.             , isHtml ? "8bit" : "base64"
  2650.             /*, rsc_save*/
  2651.             , cid);
  2652.           while((len = fread(buff, 1, sizeof(buff) - 2, fp)) > 0) {
  2653.             buff[len] = '\0';
  2654.             if (!isHtml) {
  2655.               char base64buff[60*100*2];
  2656.               code64((unsigned char*)buff, len, (unsigned char*)base64buff, 1);
  2657.               fprintf(opt->state.mimefp, "%s", base64buff);
  2658.             } else {
  2659.               fprintf(opt->state.mimefp, "%s", buff);
  2660.             }
  2661.           }
  2662.           fclose(fp);
  2663.           fprintf(opt->state.mimefp, "\r\n\r\n");
  2664.         }
  2665.       }
  2666.     } else if (save == NULL) {
  2667.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2668.         fprintf(opt->state.mimefp, 
  2669.           "--%s--\r\n", opt->state.mimemid);
  2670.         fclose(opt->state.mimefp);
  2671.         opt->state.mimefp = NULL;
  2672.       }
  2673.     }
  2674.   }
  2675. }
  2676.  
  2677. // Θcrire n espaces dans fp
  2678. typedef struct {
  2679.   int error;
  2680.   int warning;
  2681.   int info;
  2682. } fspc_strc;
  2683. HTS_INLINE int fspc(FILE* fp,char* type) {
  2684.   fspc_strc* strc;
  2685.   NOSTATIC_RESERVE(strc, fspc_strc, 1); // log..
  2686.  
  2687.   //
  2688.   if (fp) {
  2689.     char s[256];
  2690.     time_t tt;
  2691.     struct tm* A;
  2692.     tt=time(NULL);
  2693.     A=localtime(&tt);
  2694.     if (A == NULL) {
  2695.       int localtime_returned_null=0;
  2696.       assert(localtime_returned_null);
  2697.     }
  2698.     strftime(s,250,"%H:%M:%S",A);
  2699.     if (strnotempty(type))
  2700.       fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  2701.     else
  2702.       fprintf(fp,"%s\t \t",s);
  2703.     if (strcmp(type,"warning")==0)
  2704.       strc->warning++;
  2705.     else if (strcmp(type,"error")==0)
  2706.       strc->error++;
  2707.     else if (strcmp(type,"info")==0)
  2708.       strc->info++;
  2709.   } 
  2710.   else if (!type)
  2711.     strc->error=strc->warning=strc->info=0;     // reset
  2712.   else if (strcmp(type,"warning")==0)
  2713.     return strc->warning;
  2714.   else if (strcmp(type,"error")==0)
  2715.     return strc->error;
  2716.   else if (strcmp(type,"info")==0)
  2717.     return strc->info;
  2718.   return 0;
  2719. }
  2720.  
  2721.  
  2722. // vΘrifier taux de transfert
  2723. #if 0
  2724. void check_rate(TStamp stat_timestart,int maxrate) {
  2725.   // vΘrifier taux de transfert (pas trop grand?)
  2726.   /*
  2727.   if (maxrate>0) {
  2728.     int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart));    // taux actuel de transfert
  2729.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  2730.     if (r>maxrate) {    // taux>taux autorisΘ
  2731.       int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
  2732.       if (taux<15)
  2733.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  2734.       else if (taux<50)
  2735.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  2736.       else
  2737.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  2738.     }
  2739.   }
  2740.   */
  2741. }
  2742. #endif
  2743.  
  2744. // ---
  2745. // sous routines liΘes au moteur et au backing
  2746.  
  2747. // supplemental links ready (done) after ptr
  2748. int backlinks_done(lien_url** liens,int lien_tot,int ptr) {
  2749.   int n=0;
  2750.   int i;
  2751.   //Links done and stored in cache
  2752.   for(i=ptr+1;i<lien_tot;i++) {
  2753.     if (liens[i]) {
  2754.       if (liens[i]->pass2 == -1) {
  2755.         n++;
  2756.       }
  2757.     }
  2758.   }
  2759.   return n;
  2760. }
  2761.  
  2762. // remplir backing si moins de max_bytes en mΘmoire
  2763. HTS_INLINE int back_fillmax(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2764.   if (!opt->state.stop) {
  2765.     if (back_incache(back,back_max)<opt->maxcache) {  // pas trop en mΘmoire?
  2766.       return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  2767.     }
  2768.   }
  2769.   return -1;                /* plus de place */
  2770. }
  2771.  
  2772. // remplir backing
  2773. int back_fill(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2774.   int n;
  2775.   // int oneLess = ( (_hts_in_html_parsing == 2 && opt->maxsoc >= 2) || (_hts_in_html_parsing == 1 && opt->maxsoc >= 4) ) ? 1 : 0;  // testing links
  2776.  
  2777.   // ajouter autant de socket qu'on peut ajouter
  2778.   n=opt->maxsoc-back_nsoc(back,back_max) /* - oneLess */;
  2779.  
  2780.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  2781.   n=min( n, back_available(back,back_max) - 8 );
  2782.  
  2783.   // no space left on backing stack - do not back anymore
  2784.   if (back_stack_available(back,back_max) <= 2)
  2785.     n=0;
  2786.  
  2787.   if (n>0) {
  2788.     int p;
  2789.  
  2790.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  2791.       cache->ptr_ant=0;
  2792.     }
  2793.  
  2794.     p=ptr+1;
  2795.     /* on a dΘja parcouru */
  2796.     if (p<cache->ptr_ant)
  2797.       p=cache->ptr_ant;
  2798.     while( (p<lien_tot) && (n>0) && back_checkmirror(opt)) {
  2799.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  2800.       int ok=1;
  2801.       
  2802.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs
  2803.       if (liens[p]->pass2) {  // 2Φ passe
  2804.         if (numero_passe!=1)
  2805.           ok=0;
  2806.       } else {
  2807.         if (numero_passe!=0)
  2808.           ok=0;
  2809.       }
  2810.       
  2811.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  2812.       // le ptr l'atteigne
  2813.       if (ok) {
  2814.         if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
  2815.           if (back_add(back,back_max,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) {
  2816.             if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  2817.               fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
  2818.               test_flush;
  2819.             }                    
  2820. #if BDEBUG==1
  2821.             printf("error while adding\n");
  2822. #endif                  
  2823.             n=0;    // sortir
  2824.           } else {
  2825.             n--;
  2826. #if BDEBUG==1
  2827.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  2828. #endif
  2829.           } 
  2830.         }
  2831.       }
  2832.       p++;
  2833.     }  // while
  2834.     /* sauver position derniΦre anticipation */
  2835.     cache->ptr_ant=p;
  2836.     cache->ptr_last=ptr;
  2837.   }
  2838.   return 0;
  2839. }
  2840. // ---
  2841.  
  2842.  
  2843.  
  2844.  
  2845.  
  2846.  
  2847.  
  2848.  
  2849.  
  2850.  
  2851.  
  2852.  
  2853.  
  2854.  
  2855.  
  2856.  
  2857.  
  2858.  
  2859. // routines de dΘtournement de SIGHUP & co (Unix)
  2860. //
  2861. httrackp* hts_declareoptbuffer(httrackp* optdecl) {
  2862.   static httrackp* opt=NULL; /* OK */
  2863.   if (optdecl) opt=optdecl;
  2864.   return opt;
  2865. }
  2866. //
  2867. void sig_finish( int code ) {       // finir et quitter
  2868.   signal(code,sig_term);  // quitter si encore
  2869.   exit_xh=1;
  2870.   fprintf(stderr,"\nExit requested to engine (signal %d)\n",code);
  2871. }
  2872. void sig_term( int code ) {       // quitter brutalement
  2873.   fprintf(stderr,"\nProgram terminated (signal %d)\n",code);
  2874.   exit(0);
  2875. }
  2876. #if HTS_WIN
  2877. void sig_ask( int code ) {        // demander
  2878.   char s[256];
  2879.   signal(code,sig_term);  // quitter si encore
  2880.   printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
  2881.   fflush(stdout);
  2882.   scanf("%s",s);
  2883.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2884.     exit(0);     // quitter
  2885.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2886.     httrackp* opt=hts_declareoptbuffer(NULL);
  2887.     if (opt) {
  2888.       // ask for stop
  2889.       opt->state.stop=1;
  2890.     }
  2891.   }
  2892.   signal(code,sig_ask);  // remettre signal
  2893. }
  2894. #else
  2895. void sig_back( int code ) {       // ignorer et mettre en backing 
  2896.   signal(code,sig_ignore);
  2897.   sig_doback(0);
  2898. }
  2899. void sig_ask( int code ) {        // demander
  2900.   char s[256];
  2901.   signal(code,sig_term);  // quitter si encore
  2902.   printf("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
  2903.   fflush(stdout);
  2904.   scanf("%s",s);
  2905.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2906.     exit(0);     // quitter
  2907.   else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
  2908.     sig_doback(0);  // arriΦre plan
  2909.   else if ( (s[0]=='l') || (s[0]=='L') )
  2910.     sig_doback(1);  // arriΦre plan
  2911.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2912.     httrackp* opt=hts_declareoptbuffer(NULL);
  2913.     if (opt) {
  2914.       // ask for stop
  2915.       printf("finishing pending transfers.. please wait\n");
  2916.       opt->state.stop=1;
  2917.     }
  2918.     signal(code,sig_ask);  // remettre signal
  2919.   }
  2920.   else {
  2921.     printf("cancel..\n");
  2922.     signal(code,sig_ask);  // remettre signal
  2923.   }
  2924. }
  2925. void sig_ignore( int code ) {     // ignorer signal
  2926. }
  2927. void sig_brpipe( int code ) {     // treat if necessary
  2928.   signal(code, sig_brpipe);
  2929. }
  2930. void sig_doback(int blind) {       // mettre en backing 
  2931.   int out=-1;
  2932.   //
  2933.   printf("\nMoving into background to complete the mirror...\n"); fflush(stdout);
  2934.  
  2935.   {
  2936.     httrackp* opt=hts_declareoptbuffer(NULL);
  2937.     if (opt) {
  2938.       // suppress logging and asking lousy questions
  2939.       opt->quiet=1;
  2940.       opt->verbosedisplay=0;
  2941.     }
  2942.   }
  2943.  
  2944.   if (!blind)
  2945.     out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
  2946.   if (out == -1)
  2947.     out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
  2948.   close(0);
  2949.   close(1);
  2950.   dup(out);
  2951.   close(2);
  2952.   dup(out);
  2953.   //
  2954.   switch (fork()) {
  2955.   case 0: 
  2956.     break;
  2957.   case -1:
  2958.     fprintf(stderr,"Error: can not fork process\n");
  2959.     break;
  2960.   default:            // pere
  2961.     usleep(100000);   // pause 1/10s "A  microsecond  is  .000001s"
  2962.     _exit(0);
  2963.     break;  
  2964.   }
  2965. }
  2966. #endif
  2967. // fin routines de dΘtournement de SIGHUP & co
  2968.  
  2969. // Poll stdin.. si besoin
  2970. #if HTS_POLL
  2971. // lecture stdin des caractΦres disponibles
  2972. int read_stdin(char* s,int max) {
  2973.   int i=0;
  2974.   while((check_stdin()) && (i<(max-1)) )
  2975.     s[i++]=fgetc(stdin);
  2976.   s[i]='\0';
  2977.   return i;
  2978. }
  2979. #ifdef _WIN32
  2980. HTS_INLINE int check_stdin(void) {
  2981. #ifndef _WIN32_WCE
  2982.   return (_kbhit());
  2983. #else
  2984.   return 0;
  2985. #endif
  2986. }
  2987. #else
  2988. HTS_INLINE int check_flot(T_SOC s) {
  2989.   fd_set fds;
  2990.   struct timeval tv;
  2991.   FD_ZERO(&fds);
  2992.   FD_SET((T_SOC) s,&fds);
  2993.   tv.tv_sec=0;
  2994.   tv.tv_usec=0;
  2995.   select(s+1,&fds,NULL,NULL,&tv);
  2996.   return FD_ISSET(s,&fds);
  2997. }
  2998. HTS_INLINE int check_stdin(void) {
  2999.   fflush(stdout); fflush(stdin);
  3000.   if (check_flot(0))
  3001.     return 1;
  3002.   return 0;
  3003. }
  3004. #endif
  3005. #endif
  3006.  
  3007. HTS_INLINE int check_sockerror(T_SOC s) {
  3008.   fd_set fds;
  3009.   struct timeval tv;
  3010.   FD_ZERO(&fds);
  3011.   FD_SET((T_SOC) s,&fds);
  3012.   tv.tv_sec=0;
  3013.   tv.tv_usec=0;
  3014.   select(s+1,NULL,NULL,&fds,&tv);
  3015.   return FD_ISSET(s,&fds);
  3016. }
  3017.  
  3018. /* check incoming data */
  3019. HTS_INLINE int check_sockdata(T_SOC s) {
  3020.   fd_set fds;
  3021.   struct timeval tv;
  3022.   FD_ZERO(&fds);
  3023.   FD_SET((T_SOC) s,&fds);
  3024.   tv.tv_sec=0;
  3025.   tv.tv_usec=0;
  3026.   select(s+1,&fds,NULL,NULL,&tv);
  3027.   return FD_ISSET(s,&fds);
  3028. }
  3029.  
  3030. // Attente de touche
  3031. #if HTS_ANALYSTE
  3032. int ask_continue(void) {
  3033.   char* s;
  3034.   s=hts_htmlcheck_query2(HTbuff);
  3035.   if (s) {
  3036.     if (strnotempty(s)) {
  3037.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3038.         return 0;
  3039.     }
  3040.     return 1;
  3041.   }
  3042.   return 1;
  3043. }
  3044. #else
  3045. int ask_continue(void) {
  3046.   char s[12];
  3047.   s[0]='\0';
  3048.   printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
  3049.   io_flush; linput(stdin,s,4);
  3050.   if (strnotempty(s)) {
  3051.     if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3052.       return 0;
  3053.   }
  3054.   return 1;
  3055. }
  3056. #endif
  3057.  
  3058. // nombre de digits dans un nombre
  3059. int nombre_digit(int n) {
  3060.   int i=1;
  3061.   while(n >= 10) { n/=10; i++; }
  3062.   return i;
  3063. }
  3064.  
  3065.  
  3066. // renvoi adresse de la fin du token dans p
  3067. // renvoi NULL si la chaine est un token unique
  3068. // (PATCHE Θgalement la chaine)
  3069. // ex: "test" "test2" renvoi adresse sur espace
  3070. // flag==1 si chaine comporte des echappements comme \"
  3071. char* next_token(char* p,int flag) {
  3072.   int detect=0;
  3073.   int quote=0;
  3074.   p--;
  3075.   do {
  3076.     p++;
  3077.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3078.       if (quote) {
  3079.         char c='\0';
  3080.         if (*(p+1)=='\\')
  3081.           c='\\';
  3082.         else if (*(p+1)=='"')
  3083.           c='"';
  3084.         if (c) {
  3085.           char tempo[8192];
  3086.           tempo[0]=c; tempo[1]='\0';
  3087.           strcatbuff(tempo,p+2);
  3088.           strcpybuff(p,tempo);
  3089.         }
  3090.       }
  3091.     }
  3092.     else if (*p==34) {  // guillemets (de fin)
  3093.       char tempo[8192];
  3094.       tempo[0]='\0';
  3095.       strcatbuff(tempo,p+1);
  3096.       strcpybuff(p,tempo);   /* wipe "" */
  3097.       p--;
  3098.       /* */
  3099.       quote=!quote;
  3100.     }
  3101.     else if (*p==32) {
  3102.       if (!quote)
  3103.         detect=1;
  3104.     }
  3105.     else if (*p=='\0') {
  3106.       p=NULL;
  3107.       detect=1;
  3108.     }
  3109.   } while(!detect);
  3110.   return p;
  3111. }
  3112.  
  3113. // routines annexes 
  3114. #if HTS_ANALYSTE
  3115. // canceller un fichier (noter comme cancellable)
  3116. // !!NOT THREAD SAFE!!
  3117. HTSEXT_API char* hts_cancel_file(char * s) {
  3118.   static char sav[HTS_URLMAXSIZE*2]="";
  3119.   if (s[0]!='\0')
  3120.   if (sav[0]=='\0')
  3121.     strcpybuff(sav,s);
  3122.   return sav;
  3123. }
  3124. HTSEXT_API void hts_cancel_test(void) {
  3125.   if (_hts_in_html_parsing==2)
  3126.     _hts_cancel=2;
  3127. }
  3128. HTSEXT_API void hts_cancel_parsing(void) {
  3129.   if (_hts_in_html_parsing)
  3130.    _hts_cancel=1;
  3131. }
  3132. #endif
  3133. //        for(_i=0;(_i<back_max) && (index<NStatsBuffer);_i++) {
  3134. //          i=(back_index+_i)%back_max;    // commencer par le "premier" (l'actuel)
  3135. //          if (back[i].status>=0) {     // signifie "lien actif"
  3136.  
  3137. #if 0
  3138. /*  
  3139. hts_add_file, add/get elements in the add chain for java parsing
  3140. if file_position >= 0
  3141.   push 'file/file_position'
  3142.   return 1 (return 0 if exists)
  3143. else
  3144.   pop file -> 'file'
  3145.   return 'file_position'
  3146. else if empty/error
  3147.   return -1;
  3148. */
  3149. typedef struct addfile_chain {
  3150.   char name[1024];
  3151.   int pos;
  3152.   struct addfile_chain* next;
  3153. } addfile_chain;
  3154. typedef addfile_chain* addfile_chain_ptr;
  3155. int opt->(char* file,int file_position) {
  3156.   addfile_chain** chain;
  3157.   NOSTATIC_RESERVE(chain, addfile_chain_ptr, 1);
  3158.  
  3159.   if (file_position>=0) {         /* copy file to the chain */
  3160.     struct addfile_chain** current;
  3161.     current=chain;                     /* start from */
  3162.     while(*current) {
  3163.       if (strcmp((*current)->name,file)==0)
  3164.         return 0;                       /* already exists */
  3165.       current=&( (*current)->next );    /* 'next' address */
  3166.     }
  3167.     *current=calloct(1,sizeof(addfile_chain));
  3168.     if (*current) {
  3169.       (*current)->next=NULL;
  3170.       (*current)->pos=-1;
  3171.       (*current)->name[0]='\0';
  3172.     }
  3173.     if (*current) {
  3174.       strcpybuff((*current)->name,file);
  3175.       (*current)->pos=file_position;
  3176.       return 1;
  3177.     } else {
  3178.       printf("PANIC! Too many Java files during parsing [1]\n");
  3179.       return -1;
  3180.     }
  3181.   } else {                      /* copy last element in file and delete it */
  3182.     if (file)
  3183.       file[0]='\0';
  3184.     if (*chain) {
  3185.       struct addfile_chain** current;
  3186.       int pos=-1;
  3187.       current=chain;                     /* start from */
  3188.       while( (*current)->next ) {
  3189.         current=&( (*current)->next );    /* 'next' address */
  3190.       }
  3191.       if (file)
  3192.         strcpybuff(file,(*current)->name);
  3193.       pos=(*current)->pos;
  3194.       freet(*current);
  3195.       *current=NULL;
  3196.       return pos;
  3197.     }
  3198.     return -1;                            /* no more elements */
  3199.   }
  3200.  
  3201.   return 0;
  3202. }
  3203. #endif
  3204.  
  3205. #if HTS_ANALYSTE
  3206. // en train de parser un fichier html? rΘponse: % effectuΘs
  3207. // flag>0 : refresh demandΘ
  3208. HTSEXT_API int hts_is_parsing(int flag) {
  3209.   if (_hts_in_html_parsing) {  // parsing?
  3210.     if (flag>=0) _hts_in_html_poll=1;  // faudrait un tit refresh
  3211.     return max(_hts_in_html_done,1); // % effectuΘs
  3212.   } else {
  3213.     return 0;                 // non
  3214.   }
  3215. }
  3216. HTSEXT_API int hts_is_testing(void) {            // 0 non 1 test 2 purge
  3217.   if (_hts_in_html_parsing==2)
  3218.     return 1;
  3219.   else if (_hts_in_html_parsing==3)
  3220.     return 2;
  3221.   else if (_hts_in_html_parsing==4)
  3222.     return 3;
  3223.   return 0;
  3224. }
  3225. HTSEXT_API int hts_is_exiting(void) {
  3226.   return exit_xh;
  3227. }
  3228. // message d'erreur?
  3229. char* hts_errmsg(void) {
  3230.   return _hts_errmsg;
  3231. }
  3232. // mode pause transfer
  3233. HTSEXT_API int hts_setpause(int p) {
  3234.   if (p>=0) _hts_setpause=p;
  3235.   return _hts_setpause;
  3236. }
  3237. // ask for termination
  3238. HTSEXT_API int hts_request_stop(int force) {
  3239.   httrackp* opt=hts_declareoptbuffer(NULL);
  3240.   if (opt) {
  3241.     opt->state.stop=1;
  3242.   }
  3243.   return 0;
  3244. }
  3245. // rΘgler en cours de route les paramΦtres rΘglables..
  3246. // -1 : erreur
  3247. HTSEXT_API int hts_setopt(httrackp* set_opt) {
  3248.   if (set_opt) {
  3249.     httrackp* engine_opt=hts_declareoptbuffer(NULL);
  3250.     if (engine_opt) {
  3251.       //_hts_setopt=opt;
  3252.       copy_htsopt(set_opt,engine_opt);
  3253.     }
  3254.   }
  3255.   return 0;
  3256. }
  3257. // ajout d'URL
  3258. // -1 : erreur
  3259. HTSEXT_API int hts_addurl(char** url) {
  3260.   if (url) _hts_addurl=url;
  3261.   return (_hts_addurl!=NULL);
  3262. }
  3263. HTSEXT_API int hts_resetaddurl(void) {
  3264.   _hts_addurl=NULL;
  3265.   return (_hts_addurl!=NULL);
  3266. }
  3267. // copier nouveaux paramΦtres si besoin
  3268. HTSEXT_API int copy_htsopt(httrackp* from,httrackp* to) {
  3269.   if (from->maxsite > -1) 
  3270.     to->maxsite = from->maxsite;
  3271.   
  3272.   if (from->maxfile_nonhtml > -1) 
  3273.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3274.   
  3275.   if (from->maxfile_html > -1) 
  3276.     to->maxfile_html = from->maxfile_html;
  3277.   
  3278.   if (from->maxsoc > 0) 
  3279.     to->maxsoc = from->maxsoc;
  3280.   
  3281.   if (from->nearlink > -1) 
  3282.     to->nearlink = from->nearlink;
  3283.   
  3284.   if (from->timeout > -1) 
  3285.     to->timeout = from->timeout;
  3286.   
  3287.   if (from->rateout > -1)
  3288.     to->rateout = from->rateout;
  3289.   
  3290.   if (from->maxtime > -1) 
  3291.     to->maxtime = from->maxtime;
  3292.   
  3293.   if (from->maxrate > -1)
  3294.     to->maxrate = from->maxrate;
  3295.   
  3296.   if (strnotempty(from->user_agent)) 
  3297.     strcpybuff(to->user_agent , from->user_agent);
  3298.   
  3299.   if (from->retry > -1) 
  3300.     to->retry = from->retry;
  3301.   
  3302.   if (from->hostcontrol > -1) 
  3303.     to->hostcontrol = from->hostcontrol;
  3304.   
  3305.   if (from->errpage > -1) 
  3306.     to->errpage = from->errpage;
  3307.  
  3308.   if (from->parseall > -1) 
  3309.     to->parseall = from->parseall;
  3310.  
  3311.  
  3312.   // test all: bit 8 de travel
  3313.   if (from->travel > -1)  {
  3314.     if (from->travel & 256)
  3315.       to->travel|=256;
  3316.     else
  3317.       to->travel&=255;
  3318.   }
  3319.  
  3320.  
  3321.   return 0;
  3322. }
  3323.  
  3324. #endif
  3325. //
  3326.  
  3327. /* External modules callback */
  3328. int htsAddLink(htsmoduleStruct* str, char* link) {
  3329.   if (link != NULL && str != NULL && link[0] != '\0') {
  3330.     lien_url** liens = (lien_url**) str->liens;
  3331.     httrackp* opt = (httrackp*) str->opt;
  3332.     lien_back* back = (lien_back*) str->back;
  3333.     cache_back* cache = (cache_back*) str->cache;
  3334.     hash_struct* hashptr = (hash_struct*) str->hashptr;
  3335.     int back_max = str->back_max;
  3336.     int numero_passe = str->numero_passe;
  3337.     int add_tab_alloc = str->add_tab_alloc;
  3338.     /* */
  3339.     int lien_tot = * ( (int*) (str->lien_tot_) );
  3340.     int ptr = * ( (int*) (str->ptr_) );
  3341.     int lien_size = * ( (int*) (str->lien_size_) );
  3342.     char* lien_buffer = * ( (char**) (str->lien_buffer_) );
  3343.     /* */
  3344.     /* */
  3345.     char adr[HTS_URLMAXSIZE*2],
  3346.       fil[HTS_URLMAXSIZE*2],
  3347.       save[HTS_URLMAXSIZE*2];
  3348.     char codebase[HTS_URLMAXSIZE*2];
  3349.     /* */
  3350.     int pass_fix, prio_fix;
  3351.     /* */
  3352.     int forbidden_url = 1;
  3353.     
  3354.     codebase[0]='\0';
  3355.     
  3356.     if ((opt->debug>1) && (opt->log!=NULL)) {
  3357.       fspc(opt->log,"debug"); fprintf(opt->log,"(module): adding link : '%s'"LF, link); test_flush;
  3358.     }
  3359.     // recopie de "creer le lien"
  3360.     //    
  3361.  
  3362. #if HTS_ANALYSTE
  3363.   if (!hts_htmlcheck_linkdetected(link)) {
  3364.     if (opt->errlog) {
  3365.       fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper"LF, link);
  3366.       test_flush;
  3367.     }
  3368.     return 0;
  3369.   }
  3370. #endif
  3371.  
  3372.     // adr = c'est la mΩme
  3373.     // fil et save: save2 et fil2
  3374.     prio_fix=maximum(liens[ptr]->depth-1,0);
  3375.     pass_fix=max(liens[ptr]->pass2,numero_passe);
  3376.     if (liens[ptr]->cod) strcpybuff(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  3377.     if (strnotempty(codebase)==0) {    // pas de codebase, construire
  3378.       char* a;
  3379.       if (str->relativeToHtmlLink == 0)
  3380.         strcpybuff(codebase,liens[ptr]->fil);
  3381.       else
  3382.         strcpybuff(codebase,liens[liens[ptr]->precedent]->fil);
  3383.       a=codebase+strlen(codebase)-1;
  3384.       while((*a) && (*a!='/') && ( a > codebase)) a--;
  3385.       if (*a=='/')
  3386.         *(a+1)='\0';    // couper
  3387.     } else {    // couper http:// Θventuel
  3388.       if (strfield(codebase,"http://")) {
  3389.         char tempo[HTS_URLMAXSIZE*2];
  3390.         char* a=codebase+7;
  3391.         a=strchr(a,'/');    // aprΦs host
  3392.         if (a) {  // ** msg erreur et vΘrifier?
  3393.           strcpybuff(tempo,a);
  3394.           strcpybuff(codebase,tempo);    // couper host
  3395.         } else {
  3396.           if (opt->errlog) {   
  3397.             fprintf(opt->errlog,"Unexpected strstr error in base %s"LF,codebase);
  3398.             test_flush;
  3399.           }
  3400.         }
  3401.       }
  3402.     }
  3403.     
  3404.     if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  3405.       if (opt->errlog) {   
  3406.         fprintf(opt->errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
  3407.         test_flush;
  3408.       }
  3409.     }
  3410.     
  3411.     {
  3412.       char* lien = link;
  3413.       int dejafait=0;
  3414.       
  3415.       if (strnotempty(lien) && strlen(lien) < HTS_URLMAXSIZE) {
  3416.         
  3417.         // calculer les chemins et noms de sauvegarde
  3418.         if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  3419.           int r;
  3420.           int set_prio_to = 0;
  3421.           int just_test_it = 0;
  3422.           forbidden_url = hts_acceptlink(opt, ptr, lien_tot, liens,
  3423.             adr,fil,
  3424.             NULL, NULL,
  3425.             &set_prio_to,
  3426.             &just_test_it);
  3427.           if ((opt->debug>1) && (opt->log!=NULL)) {
  3428.             fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard external module link: %d"LF,forbidden_url);
  3429.             test_flush;
  3430.           }
  3431.  
  3432.           /* Link accepted */
  3433.           if (!forbidden_url) {
  3434.             char tempo[HTS_URLMAXSIZE*2];
  3435.             int a,b;
  3436.             tempo[0]='\0';
  3437.             a=opt->savename_type;
  3438.             b=opt->savename_83;
  3439.             opt->savename_type=0;
  3440.             opt->savename_83=0;
  3441.             // note: adr,fil peuvent Ωtre patchΘs
  3442.             r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,opt,liens,lien_tot,back,back_max,cache,hashptr,ptr,numero_passe);
  3443.             opt->savename_type=a;
  3444.             opt->savename_83=b;
  3445.             if (r != -1) {
  3446.               if (savename) {
  3447.                 if (lienrelatif(tempo,save,savename)==0) {
  3448.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3449.                     fspc(opt->log,"debug"); fprintf(opt->log,"(module): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  3450.                     test_flush;
  3451.                     if (str->localLink && str->localLinkSize > (int) strlen(tempo) + 1) {
  3452.                       strcpybuff(str->localLink, tempo);
  3453.                     }
  3454.                   }
  3455.                 }
  3456.               }
  3457.             }
  3458.           } else {
  3459.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3460.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): file not caught: %s"LF,lien); test_flush;
  3461.             }
  3462.             if (str->localLink && str->localLinkSize > (int) ( strlen(adr) + strlen(fil) +  8 ) ) {
  3463.               str->localLink[0] = '\0';
  3464.               if (!link_has_authority(adr))
  3465.                 strcpybuff(str->localLink,"http://");
  3466.               strcatbuff(str->localLink, adr);
  3467.               strcatbuff(str->localLink, fil);
  3468.             }
  3469.             r=-1;
  3470.           }
  3471.           //
  3472.           if (r != -1) {
  3473.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3474.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  3475.             }
  3476.             
  3477.             // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  3478.             
  3479.             // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  3480.             // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  3481.             // au fichier est la plus grande des deux prioritΘs
  3482.             //
  3483.             // On part de la fin et on essaye de se presser (Θconomise temps machine)
  3484. #if HTS_HASH
  3485.             {
  3486.               int i=hash_read(hashptr,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  3487.               if (i>=0) {
  3488.                 liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3489.                 dejafait=1;
  3490.               }
  3491.             }
  3492. #else
  3493.             {
  3494.               int l;
  3495.               int i;
  3496.               l=strlen(save);
  3497.               for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
  3498.                 if (liens[i]->sav_len==l) {    // mΩme taille de chaεne
  3499.                   if (strcmp(liens[i]->sav,save)==0) {    // existe dΘja
  3500.                     liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3501.                     dejafait=1;
  3502.                   }
  3503.                 }
  3504.               }
  3505.             }
  3506. #endif
  3507.             
  3508.             
  3509.             if (!dejafait) {
  3510.               //
  3511.               // >>>> CREER LE LIEN JAVA <<<<
  3512.               
  3513.               // enregistrer fichier (MACRO)
  3514.               liens_record(adr,fil,save,"","",opt->urlhack);
  3515.               if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  3516.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3517.                 if (opt->errlog) { 
  3518.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3519.                   test_flush;
  3520.                 }
  3521.                 exit_xh=-1;    /* fatal error -> exit */
  3522.                 return 0;
  3523.               }  
  3524.               
  3525.               // mode test?                          
  3526.               liens[lien_tot]->testmode=0;          // pas mode test
  3527.               
  3528.               liens[lien_tot]->link_import=0;       // pas mode import
  3529.               
  3530.               // Θcrire autres paramΦtres de la structure-lien
  3531.               //if (meme_adresse)                                 
  3532.               liens[lien_tot]->premier=liens[ptr]->premier;
  3533.               //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  3534.               //  liens[lien_tot]->premier=ptr;
  3535.               
  3536.               liens[lien_tot]->precedent=ptr;
  3537.               // noter la prioritΘ
  3538.               if (!set_prio_to)
  3539.                 liens[lien_tot]->depth=prio_fix;
  3540.               else
  3541.                 liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  3542.               liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  3543.               liens[lien_tot]->retry=opt->retry;
  3544.               
  3545.               //strcpybuff(liens[lien_tot]->adr,adr);
  3546.               //strcpybuff(liens[lien_tot]->fil,fil);
  3547.               //strcpybuff(liens[lien_tot]->sav,save); 
  3548.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3549.                 fspc(opt->log,"debug"); fprintf(opt->log,"(module): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  3550.                 test_flush;
  3551.               }
  3552.               
  3553.               lien_tot++;  // UN LIEN DE PLUS
  3554.             }
  3555.           }
  3556.         }
  3557.       }
  3558.     }
  3559.     
  3560.     /* Apply changes */
  3561.     * ( (int*) (str->lien_tot_) ) = lien_tot;
  3562.     * ( (int*) (str->ptr_) ) = ptr;
  3563.     * ( (int*) (str->lien_size_) ) = lien_size;
  3564.     * ( (char**) (str->lien_buffer_) ) = lien_buffer;
  3565.     return (forbidden_url == 0);
  3566.   }
  3567.   return 0;
  3568. }
  3569.  
  3570.  
  3571.  
  3572.  
  3573.  
  3574. // message copyright interne
  3575. void voidf(void) {
  3576.   char* a;
  3577.   a=""CRLF""CRLF;
  3578.   a="+-----------------------------------------------+"CRLF;
  3579.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3580.   a="|                      HTTrack Website Copier   |"CRLF;
  3581.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3582.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3583.   a="|                .class Parser Yann Philippot   |"CRLF;
  3584.   a="|                                               |"CRLF;
  3585.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3586.   a="|                           Linux PC            |"CRLF;
  3587.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3588.   a="|                           AIX 4               |"CRLF;
  3589.   a="|                                               |"CRLF;
  3590.   a="|Copyright (C) Xavier Roche and other           |"CRLF;
  3591.   a="|contributors                                   |"CRLF;
  3592.   a="|                                               |"CRLF;
  3593.   a="|Use this program at your own risks!            |"CRLF;    
  3594.   a="+-----------------------------------------------+"CRLF;
  3595.   a=""CRLF;
  3596. }
  3597.  
  3598.  
  3599. // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
  3600. //
  3601.  
  3602.